Project import generated by Copybara. GitOrigin-RevId: bcecee014ba3ad28befeacbb53623051ffc6d209 Change-Id: I2fa3967852cdbf2618afa0a4ee0a6e4b00dcd53c
diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..1522857 --- /dev/null +++ b/.bazelrc
@@ -0,0 +1 @@ +build --action_env=BAZEL_CXXOPTS=-std=c++20 \ No newline at end of file
diff --git a/.dockerignore b/.dockerignore index d8f642c..bc549d9 100644 --- a/.dockerignore +++ b/.dockerignore
@@ -1,5 +1,7 @@ ** +!common/ +common/target/ !nearby/.cargo !nearby/connections/ !nearby/crypto/ @@ -12,3 +14,4 @@ !nearby/deny.toml !nearby/rustfmt.toml !third_party +third_party/boringssl/build
diff --git a/.gitignore b/.gitignore index c1baf38..8a38822 100644 --- a/.gitignore +++ b/.gitignore
@@ -11,3 +11,4 @@ nearby/connections/ukey2/ukey2_c_ffi/cpp/build/ nearby/presence/ldt_np_jni/java/LdtNpJni/build/ **/auth_token.txt +/bazel-*
diff --git a/.gitmodules b/.gitmodules index ed737f5..f3a15fb 100644 --- a/.gitmodules +++ b/.gitmodules
@@ -7,6 +7,7 @@ [submodule "third_party/boringssl"] path = third_party/boringssl url = https://boringssl.googlesource.com/boringssl + branch = master [submodule "third_party/fuzztest"] path = third_party/fuzztest url = https://github.com/google/fuzztest.git
diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..eb6e7aa --- /dev/null +++ b/BUILD
@@ -0,0 +1,297 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@crate_index//:defs.bzl", "aliases") +load("@rules_rust//rust:defs.bzl", "rust_library") + +cc_binary( + name = "np_cpp_sample", + srcs = ["nearby/presence/np_cpp_ffi/sample/main.cc"], + copts = [ + "-Inearby/presence/np_c_ffi/include/cpp", + "-Inearby/presence/np_cpp_ffi/include", + ], + deps = [ + ":np_c_ffi_types", + ":np_cpp_ffi", + "@absl//absl/strings", + ], +) + +cc_library( + name = "np_cpp_ffi", + srcs = ["nearby/presence/np_cpp_ffi/nearby_protocol.cc"], + hdrs = ["nearby/presence/np_cpp_ffi/include/nearby_protocol.h"], + copts = [ + "-Inearby/presence/np_cpp_ffi/include", + "-Inearby/presence/np_c_ffi/include/cpp", + ], + deps = [ + ":np_c_ffi", + "@absl//absl/status", + "@absl//absl/status:statusor", + "@absl//absl/strings", + "@absl//absl/strings:str_format", + ], +) + +cc_library( + name = "np_c_ffi", + hdrs = [ + "nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h", + "nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h", + ], + deps = [":np_c_ffi_rust"], +) + +cc_library( + name = "np_c_ffi_types", + hdrs = ["nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h"], +) + +rust_library( + name = "np_c_ffi_rust", + srcs = glob(include = ["nearby/presence/np_c_ffi/src/**/*.rs"]), + crate_features = ["std"], + deps = [ + ":lock_adapter", + ":np_ffi_core", + ], +) + +rust_library( + name = "np_ffi_core", + srcs = glob(include = ["nearby/presence/np_ffi_core/src/**/*.rs"]), + crate_features = ["crypto_provider/raw_private_key_permit"], + proc_macro_deps = ["@crate_index//:strum_macros"], + deps = [ + ":array_view", + ":crypto_provider", + ":crypto_provider_default", + ":handle_map", + ":ldt_np_adv", + ":lock_adapter", + ":np_adv", + ":np_adv_dynamic", + ":np_hkdf", + "@crate_index//:lazy_static", + "@crate_index//:strum", + ], +) + +rust_library( + name = "np_adv_dynamic", + srcs = glob(include = ["nearby/presence/np_adv_dynamic/src/**/*.rs"]), + deps = [ + ":array_view", + ":crypto_provider", + ":np_adv", + ":sink", + "@crate_index//:thiserror", + ], +) + +rust_library( + name = "handle_map", + srcs = glob(include = ["common/handle_map/src/**/*.rs"]), + deps = [":lock_adapter"], +) + +rust_library( + name = "lock_adapter", + srcs = glob(include = ["common/lock_adapter/src/**/*.rs"]), + crate_features = ["std"], +) + +rust_library( + name = "np_adv", + srcs = glob(include = ["nearby/presence/np_adv/src/**/*.rs"]), + crate_features = ["alloc"], + proc_macro_deps = ["@crate_index//:strum_macros"], + deps = [ + ":array_view", + ":crypto_provider", + ":ldt", + ":ldt_np_adv", + ":np_ed25519", + ":np_hkdf", + ":sink", + ":xts_aes", + "@crate_index//:lazy_static", + "@crate_index//:nom", + "@crate_index//:strum", + "@crate_index//:tinyvec", + ], +) + +rust_library( + name = "np_ed25519", + srcs = glob( + include = ["nearby/presence/np_ed25519/src/**/*.rs"], + ), + deps = [ + ":array_view", + ":crypto_provider", + ":ldt", + ":sink", + ":xts_aes", + "@crate_index//:tinyvec", + ], +) + +cc_binary( + name = "main", + srcs = ["nearby/presence/ldt_np_adv_ffi/c/sample/main.c"], + deps = [":ldt_np_adv_ffi"], +) + +cc_library( + name = "ldt_np_adv_ffi", + hdrs = ["nearby/presence/ldt_np_adv_ffi/c/include/np_ldt.h"], + includes = ["nearby/presence/ldt_np_adv_ffi/c/include"], + deps = [":ldt_np_adv_ffi_rust"], +) + +rust_library( + name = "ldt_np_adv_ffi_rust", + srcs = glob(["nearby/presence/ldt_np_adv_ffi/src/**/*.rs"]), + crate_features = ["std"], + deps = [ + ":crypto_provider", + ":crypto_provider_default", + ":ldt", + ":ldt_np_adv", + ":np_hkdf", + "@crate_index//:cfg-if", + "@crate_index//:lazy_static", + ], +) + +rust_library( + name = "ldt_np_adv", + srcs = glob(["nearby/presence/ldt_np_adv/src/**/*.rs"]), + deps = [ + ":array_view", + ":crypto_provider", + ":ldt", + ":np_hkdf", + ":xts_aes", + ], +) + +rust_library( + name = "np_hkdf", + srcs = glob(["nearby/presence/np_hkdf/src/**/*.rs"]), + deps = [ + ":crypto_provider", + ":ldt", + ":xts_aes", + ], +) + +rust_library( + name = "crypto_provider", + srcs = glob(["nearby/crypto/crypto_provider/src/**/*.rs"]), + crate_features = [ + "raw_private_key_permit", + "std", + "alloc", + ], + deps = ["@crate_index//:tinyvec"], +) + +rust_library( + name = "crypto_provider_default", + srcs = glob(["nearby/crypto/crypto_provider_default/src/**/*.rs"]), + crate_features = [ + "rustcrypto", + "std", + ], + deps = [ + ":crypto_provider", + ":crypto_provider_rustcrypto", + "@crate_index//:cfg-if", + ], +) + +rust_library( + name = "crypto_provider_rustcrypto", + srcs = glob(["nearby/crypto/crypto_provider_rustcrypto/src/**/*.rs"]), + crate_features = [ + "std", + "alloc", + ], + deps = [ + ":crypto_provider", + "@crate_index//:aead", + "@crate_index//:aes", + "@crate_index//:aes-gcm", + "@crate_index//:aes-gcm-siv", + "@crate_index//:cbc", + "@crate_index//:cfg-if", + "@crate_index//:ctr", + "@crate_index//:ed25519-dalek", + "@crate_index//:hkdf", + "@crate_index//:hmac", + "@crate_index//:p256", + "@crate_index//:rand", + "@crate_index//:rand_chacha", + "@crate_index//:rand_core", + "@crate_index//:sec1", + "@crate_index//:sha2", + "@crate_index//:subtle", + "@crate_index//:x25519-dalek", + ], +) + +rust_library( + name = "ldt_tbc", + srcs = glob(["nearby/presence/ldt_tbc/src/**/*.rs"]), + deps = [":crypto_provider"], +) + +rust_library( + name = "ldt", + srcs = glob(["nearby/presence/ldt/src/**/*.rs"]), + deps = [ + ":crypto_provider", + ":ldt_tbc", + ], +) + +rust_library( + name = "xts_aes", + srcs = glob(["nearby/presence/xts_aes/src/**/*.rs"]), + deps = [ + ":array_ref", + ":crypto_provider", + ":ldt_tbc", + ], +) + +rust_library( + name = "array_view", + srcs = glob(["nearby/presence/array_view/src/**/*.rs"]), +) + +rust_library( + name = "array_ref", + srcs = glob(["nearby/presence/array_ref/src/**/*.rs"]), +) + +rust_library( + name = "sink", + srcs = glob(["nearby/presence/sink/src/**/*.rs"]), + deps = ["@crate_index//:tinyvec"], +)
diff --git a/Dockerfile b/Dockerfile index 1f0462e..9122d14 100644 --- a/Dockerfile +++ b/Dockerfile
@@ -12,31 +12,40 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM ubuntu:22.10 +FROM ubuntu:22.04 # install system deps -RUN apt-get update && apt-get install -y build-essential cmake gcc wget vim \ -clang git checkinstall zlib1g-dev libjsoncpp-dev libbenchmark-dev curl \ -protobuf-compiler pkg-config libdbus-1-dev libssl-dev ninja-build +RUN apt-get update && apt-get install -y build-essential wget vim libstdc++-10-dev \ +clang git checkinstall zlib1g-dev curl protobuf-compiler cmake \ +pkg-config libdbus-1-dev ninja-build libssl-dev default-jre RUN apt upgrade -y +RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +RUN apt-get -y install ./google-chrome-stable_current_amd64.deb +RUN export CHROME_BIN="/usr/bin/google-chrome-stable" + +ENV CC=/usr/bin/clang +ENV CXX=/usr/bin/clang++ + # install cargo with default settings -RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.72.0 +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.77.1 ENV PATH="/root/.cargo/bin:${PATH}" +RUN rustup install stable +RUN rustup toolchain install nightly --force +RUN rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu +RUN rustup target add wasm32-unknown-unknown thumbv7m-none-eabi + RUN cargo install --locked cargo-deny --color never 2>&1 -RUN cargo install cargo-fuzz --color never 2>&1 +RUN cargo install --locked cargo-llvm-cov --color never 2>&1 +RUN cargo install bindgen-cli --version 0.69.4 --color never 2>&1 +RUN cargo install wasm-pack --color never 2>&1 + # unreleased PR https://github.com/ehuss/cargo-prefetch/pull/6 RUN cargo install cargo-prefetch \ --git https://github.com/marshallpierce/cargo-prefetch.git \ --rev f6affa68e950275f9fd773f2646ab7ee4db82897 \ --color never 2>&1 -# needed for generating boringssl bindings -# Must use 0.64.0, as version >= 0.65.0 removes the option "--size_t-is-usize", an option -# used by boringssl when generating rust bindings -RUN cargo install bindgen-cli --version 0.64.0 -RUN cargo install wasm-pack --color never 2>&1 -RUN rustup toolchain add nightly -RUN rustup target add wasm32-unknown-unknown + # boringssl build wants go RUN curl -L https://go.dev/dl/go1.20.2.linux-amd64.tar.gz | tar -C /usr/local -xz ENV PATH="$PATH:/usr/local/go/bin" @@ -45,13 +54,20 @@ RUN git config --global user.email "docker@example.com" RUN git config --global user.name "NP Docker" -RUN mkdir -p /google -COPY . /google +# Download google-java-format +RUN mkdir /opt/google-java-format +WORKDIR /opt/google-java-format +ENV GOOGLE_JAVA_FORMAT_VERSION="1.19.2" +RUN wget "https://github.com/google/google-java-format/releases/download/v${GOOGLE_JAVA_FORMAT_VERSION}/google-java-format-${GOOGLE_JAVA_FORMAT_VERSION}-all-deps.jar" -q -O "google-java-format-all-deps.jar" -WORKDIR /google/nearby +RUN mkdir -p /beto-core +COPY . /beto-core +WORKDIR /beto-core # prefetch dependencies so later build steps don't re-download on source changes -RUN cargo prefetch --lockfile Cargo.lock +RUN cargo prefetch --lockfile nearby/Cargo.lock 2>&1 +RUN cargo prefetch --lockfile common/Cargo.lock 2>&1 # when the image runs build and test everything to ensure env is setup correctly +WORKDIR /beto-core/nearby CMD ["cargo", "run", "--", "check-everything"]
diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..1a49310 --- /dev/null +++ b/MODULE.bazel
@@ -0,0 +1,6 @@ +############################################################################### +# Bazel now uses Bzlmod by default to manage external dependencies. +# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel. +# +# For more details, please check https://github.com/bazelbuild/bazel/issues/18958 +############################################################################### \ No newline at end of file
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..7490be4 --- /dev/null +++ b/MODULE.bazel.lock
@@ -0,0 +1,1632 @@ +{ + "lockFileVersion": 6, + "moduleFileHash": "1bed0cff67b36277151f008b059508a5316fa37a0baa62d447f3e14a517b8e77", + "flags": { + "cmdRegistries": [ + "https://bcr.bazel.build/" + ], + "cmdModuleOverrides": {}, + "allowedYankedVersions": [], + "envVarAllowedYankedVersions": "", + "ignoreDevDependency": false, + "directDependenciesMode": "WARNING", + "compatibilityMode": "ERROR" + }, + "localOverrideHashes": { + "bazel_tools": "1ae69322ac3823527337acf02016e8ee95813d8d356f47060255b8956fa642f0" + }, + "moduleDepGraph": { + "<root>": { + "name": "", + "version": "", + "key": "<root>", + "repoName": "", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + } + }, + "bazel_tools@_": { + "name": "bazel_tools", + "version": "", + "key": "bazel_tools@_", + "repoName": "bazel_tools", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all", + "@local_config_sh//:local_sh_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 18, + "column": 29 + }, + "imports": { + "local_config_cc": "local_config_cc", + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", + "extensionName": "xcode_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 22, + "column": 32 + }, + "imports": { + "local_config_xcode": "local_config_xcode" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 25, + "column": 32 + }, + "imports": { + "local_jdk": "local_jdk", + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", + "extensionName": "sh_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 36, + "column": 39 + }, + "imports": { + "local_config_sh": "local_config_sh" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", + "extensionName": "remote_coverage_tools_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 40, + "column": 48 + }, + "imports": { + "remote_coverage_tools": "remote_coverage_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", + "extensionName": "remote_android_tools_extensions", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 43, + "column": 42 + }, + "imports": { + "android_gmaven_r8": "android_gmaven_r8", + "android_tools": "android_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@buildozer//:buildozer_binary.bzl", + "extensionName": "buildozer_binary", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 47, + "column": 33 + }, + "imports": { + "buildozer_binary": "buildozer_binary" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "rules_cc": "rules_cc@0.0.9", + "rules_java": "rules_java@7.4.0", + "rules_license": "rules_license@0.0.7", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_python": "rules_python@0.22.1", + "buildozer": "buildozer@6.4.0.2", + "platforms": "platforms@0.0.7", + "com_google_protobuf": "protobuf@21.7", + "zlib": "zlib@1.3", + "build_bazel_apple_support": "apple_support@1.5.0", + "local_config_platform": "local_config_platform@_" + } + }, + "local_config_platform@_": { + "name": "local_config_platform", + "version": "", + "key": "local_config_platform@_", + "repoName": "local_config_platform", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_" + } + }, + "rules_cc@0.0.9": { + "name": "rules_cc", + "version": "0.0.9", + "key": "rules_cc@0.0.9", + "repoName": "rules_cc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "rules_cc@0.0.9", + "location": { + "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", + "line": 9, + "column": 29 + }, + "imports": { + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" + ], + "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", + "strip_prefix": "rules_cc-0.0.9", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_java@7.4.0": { + "name": "rules_java", + "version": "7.4.0", + "key": "rules_java@7.4.0", + "repoName": "rules_java", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains:all", + "@local_jdk//:runtime_toolchain_definition", + "@local_jdk//:bootstrap_runtime_toolchain_definition", + "@remotejdk11_linux_toolchain_config_repo//:all", + "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk11_linux_s390x_toolchain_config_repo//:all", + "@remotejdk11_macos_toolchain_config_repo//:all", + "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk11_win_toolchain_config_repo//:all", + "@remotejdk11_win_arm64_toolchain_config_repo//:all", + "@remotejdk17_linux_toolchain_config_repo//:all", + "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk17_linux_s390x_toolchain_config_repo//:all", + "@remotejdk17_macos_toolchain_config_repo//:all", + "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk17_win_toolchain_config_repo//:all", + "@remotejdk17_win_arm64_toolchain_config_repo//:all", + "@remotejdk21_linux_toolchain_config_repo//:all", + "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk21_macos_toolchain_config_repo//:all", + "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk21_win_toolchain_config_repo//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "rules_java@7.4.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel", + "line": 19, + "column": 27 + }, + "imports": { + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", + "local_jdk": "local_jdk", + "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", + "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", + "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", + "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", + "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", + "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", + "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", + "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", + "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", + "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", + "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", + "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", + "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", + "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", + "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", + "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", + "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", + "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", + "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", + "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", + "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_java/releases/download/7.4.0/rules_java-7.4.0.tar.gz" + ], + "integrity": "sha256-l27wi0nJKXQfIBeQ5Z44B8cq2B9CjIvJU82+/1/tFes=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_license@0.0.7": { + "name": "rules_license", + "version": "0.0.7", + "key": "rules_license@0.0.7", + "repoName": "rules_license", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" + ], + "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_proto@5.3.0-21.7": { + "name": "rules_proto", + "version": "5.3.0-21.7", + "key": "rules_proto@5.3.0-21.7", + "repoName": "rules_proto", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "com_google_protobuf": "protobuf@21.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz" + ], + "integrity": "sha256-3D+yBqLLNEG0heseQjFlsjEjWh6psDG0Qzz3vB+kYN0=", + "strip_prefix": "rules_proto-5.3.0-21.7", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_python@0.22.1": { + "name": "rules_python", + "version": "0.22.1", + "key": "rules_python@0.22.1", + "repoName": "rules_python", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@bazel_tools//tools/python:autodetecting_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_python//python/extensions/private:internal_deps.bzl", + "extensionName": "internal_deps", + "usingModule": "rules_python@0.22.1", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel", + "line": 14, + "column": 30 + }, + "imports": { + "pypi__build": "pypi__build", + "pypi__click": "pypi__click", + "pypi__colorama": "pypi__colorama", + "pypi__importlib_metadata": "pypi__importlib_metadata", + "pypi__installer": "pypi__installer", + "pypi__more_itertools": "pypi__more_itertools", + "pypi__packaging": "pypi__packaging", + "pypi__pep517": "pypi__pep517", + "pypi__pip": "pypi__pip", + "pypi__pip_tools": "pypi__pip_tools", + "pypi__setuptools": "pypi__setuptools", + "pypi__tomli": "pypi__tomli", + "pypi__wheel": "pypi__wheel", + "pypi__zipp": "pypi__zipp", + "pypi__coverage_cp310_aarch64-apple-darwin": "pypi__coverage_cp310_aarch64-apple-darwin", + "pypi__coverage_cp310_aarch64-unknown-linux-gnu": "pypi__coverage_cp310_aarch64-unknown-linux-gnu", + "pypi__coverage_cp310_x86_64-apple-darwin": "pypi__coverage_cp310_x86_64-apple-darwin", + "pypi__coverage_cp310_x86_64-unknown-linux-gnu": "pypi__coverage_cp310_x86_64-unknown-linux-gnu", + "pypi__coverage_cp311_aarch64-unknown-linux-gnu": "pypi__coverage_cp311_aarch64-unknown-linux-gnu", + "pypi__coverage_cp311_x86_64-apple-darwin": "pypi__coverage_cp311_x86_64-apple-darwin", + "pypi__coverage_cp311_x86_64-unknown-linux-gnu": "pypi__coverage_cp311_x86_64-unknown-linux-gnu", + "pypi__coverage_cp38_aarch64-apple-darwin": "pypi__coverage_cp38_aarch64-apple-darwin", + "pypi__coverage_cp38_aarch64-unknown-linux-gnu": "pypi__coverage_cp38_aarch64-unknown-linux-gnu", + "pypi__coverage_cp38_x86_64-apple-darwin": "pypi__coverage_cp38_x86_64-apple-darwin", + "pypi__coverage_cp38_x86_64-unknown-linux-gnu": "pypi__coverage_cp38_x86_64-unknown-linux-gnu", + "pypi__coverage_cp39_aarch64-apple-darwin": "pypi__coverage_cp39_aarch64-apple-darwin", + "pypi__coverage_cp39_aarch64-unknown-linux-gnu": "pypi__coverage_cp39_aarch64-unknown-linux-gnu", + "pypi__coverage_cp39_x86_64-apple-darwin": "pypi__coverage_cp39_x86_64-apple-darwin", + "pypi__coverage_cp39_x86_64-unknown-linux-gnu": "pypi__coverage_cp39_x86_64-unknown-linux-gnu" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": {}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel", + "line": 15, + "column": 22 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_python//python/extensions:python.bzl", + "extensionName": "python", + "usingModule": "rules_python@0.22.1", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel", + "line": 50, + "column": 23 + }, + "imports": { + "pythons_hub": "pythons_hub" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_proto": "rules_proto@5.3.0-21.7", + "com_google_protobuf": "protobuf@21.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_python/releases/download/0.22.1/rules_python-0.22.1.tar.gz" + ], + "integrity": "sha256-pWQP3dS+sD6MH95e1xYMC6a9R359BIZhwwwGk2om/WM=", + "strip_prefix": "rules_python-0.22.1", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_python/0.22.1/patches/module_dot_bazel_version.patch": "sha256-3+VLDH9gYDzNI4eOW7mABC/LKxh1xqF6NhacLbNTucs=" + }, + "remote_patch_strip": 1 + } + } + }, + "buildozer@6.4.0.2": { + "name": "buildozer", + "version": "6.4.0.2", + "key": "buildozer@6.4.0.2", + "repoName": "buildozer", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@buildozer//:buildozer_binary.bzl", + "extensionName": "buildozer_binary", + "usingModule": "buildozer@6.4.0.2", + "location": { + "file": "https://bcr.bazel.build/modules/buildozer/6.4.0.2/MODULE.bazel", + "line": 7, + "column": 33 + }, + "imports": { + "buildozer_binary": "buildozer_binary" + }, + "devImports": [], + "tags": [ + { + "tagName": "buildozer", + "attributeValues": { + "sha256": { + "darwin-amd64": "d29e347ecd6b5673d72cb1a8de05bf1b06178dd229ff5eb67fad5100c840cc8e", + "darwin-arm64": "9b9e71bdbec5e7223871e913b65d12f6d8fa026684daf991f00e52ed36a6978d", + "linux-amd64": "8dfd6345da4e9042daa738d7fdf34f699c5dfce4632f7207956fceedd8494119", + "linux-arm64": "6559558fded658c8fa7432a9d011f7c4dcbac6b738feae73d2d5c352e5f605fa", + "windows-amd64": "e7f05bf847f7c3689dd28926460ce6e1097ae97380ac8e6ae7147b7b706ba19b" + }, + "version": "6.4.0" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/buildozer/6.4.0.2/MODULE.bazel", + "line": 8, + "column": 27 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/fmeum/buildozer/releases/download/v6.4.0.2/buildozer-v6.4.0.2.tar.gz" + ], + "integrity": "sha256-k7tFKQMR2AygxpmZfH0yEPnQmF3efFgD9rBPkj+Yz/8=", + "strip_prefix": "buildozer-6.4.0.2", + "remote_patches": { + "https://bcr.bazel.build/modules/buildozer/6.4.0.2/patches/module_dot_bazel_version.patch": "sha256-gKANF2HMilj7bWmuXs4lbBIAAansuWC4IhWGB/CerjU=" + }, + "remote_patch_strip": 1 + } + } + }, + "platforms@0.0.7": { + "name": "platforms", + "version": "0.0.7", + "key": "platforms@0.0.7", + "repoName": "platforms", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" + ], + "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "protobuf@21.7": { + "name": "protobuf", + "version": "21.7", + "key": "protobuf@21.7", + "repoName": "protobuf", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", + "extensionName": "maven", + "usingModule": "protobuf@21.7", + "location": { + "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel", + "line": 22, + "column": 22 + }, + "imports": { + "maven": "maven" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "maven", + "artifacts": [ + "com.google.code.findbugs:jsr305:3.0.2", + "com.google.code.gson:gson:2.8.9", + "com.google.errorprone:error_prone_annotations:2.3.2", + "com.google.j2objc:j2objc-annotations:1.3", + "com.google.guava:guava:31.1-jre", + "com.google.guava:guava-testlib:31.1-jre", + "com.google.truth:truth:1.1.2", + "junit:junit:4.13.2", + "org.mockito:mockito-core:4.3.1" + ] + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel", + "line": 24, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_python": "rules_python@0.22.1", + "rules_cc": "rules_cc@0.0.9", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_java": "rules_java@7.4.0", + "rules_pkg": "rules_pkg@0.7.0", + "com_google_abseil": "abseil-cpp@20211102.0", + "zlib": "zlib@1.3", + "upb": "upb@0.0.0-20220923-a547704", + "rules_jvm_external": "rules_jvm_external@4.4.2", + "com_google_googletest": "googletest@1.11.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.zip" + ], + "integrity": "sha256-VJOiH17T/FAuZv7GuUScBqVRztYwAvpIkDxA36jeeko=", + "strip_prefix": "protobuf-21.7", + "remote_patches": { + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel.patch": "sha256-q3V2+eq0v2XF0z8z+V+QF4cynD6JvHI1y3kI/+rzl5s=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel_for_examples.patch": "sha256-O7YP6s3lo/1opUiO0jqXYORNHdZ/2q3hjz1QGy8QdIU=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/relative_repo_names.patch": "sha256-RK9RjW8T5UJNG7flIrnFiNE9vKwWB+8uWWtJqXYT0w4=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_missing_files.patch": "sha256-Hyne4DG2u5bXcWHNxNMirA2QFAe/2Cl8oMm1XJdkQIY=" + }, + "remote_patch_strip": 1 + } + } + }, + "zlib@1.3": { + "name": "zlib", + "version": "1.3", + "key": "zlib@1.3", + "repoName": "zlib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" + ], + "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", + "strip_prefix": "zlib-1.3", + "remote_patches": { + "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", + "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" + }, + "remote_patch_strip": 0 + } + } + }, + "apple_support@1.5.0": { + "name": "apple_support", + "version": "1.5.0", + "key": "apple_support@1.5.0", + "repoName": "build_bazel_apple_support", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_apple_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", + "extensionName": "apple_cc_configure_extension", + "usingModule": "apple_support@1.5.0", + "location": { + "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", + "line": 17, + "column": 35 + }, + "imports": { + "local_config_apple_cc": "local_config_apple_cc", + "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" + ], + "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "bazel_skylib@1.3.0": { + "name": "bazel_skylib", + "version": "1.3.0", + "key": "bazel_skylib@1.3.0", + "repoName": "bazel_skylib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains/unittest:cmd_toolchain", + "//toolchains/unittest:bash_toolchain" + ], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz" + ], + "integrity": "sha256-dNVE2W9KW7Yw1GXKi7z+Ix41lOWq5X4e2/F6brPKJQY=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_pkg@0.7.0": { + "name": "rules_pkg", + "version": "0.7.0", + "key": "rules_pkg@0.7.0", + "repoName": "rules_pkg", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_python": "rules_python@0.22.1", + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz" + ], + "integrity": "sha256-iimOgydi7aGDBZfWT+fbWBeKqEzVkm121bdE1lWJQcI=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/patches/module_dot_bazel.patch": "sha256-4OaEPZwYF6iC71ZTDg6MJ7LLqX7ZA0/kK4mT+4xKqiE=" + }, + "remote_patch_strip": 0 + } + } + }, + "abseil-cpp@20211102.0": { + "name": "abseil-cpp", + "version": "20211102.0", + "key": "abseil-cpp@20211102.0", + "repoName": "abseil-cpp", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_cc": "rules_cc@0.0.9", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz" + ], + "integrity": "sha256-3PcbnLqNwMqZQMSzFqDHlr6Pq0KwcLtrfKtitI8OZsQ=", + "strip_prefix": "abseil-cpp-20211102.0", + "remote_patches": { + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/patches/module_dot_bazel.patch": "sha256-4izqopgGCey4jVZzl/w3M2GVPNohjh2B5TmbThZNvPY=" + }, + "remote_patch_strip": 0 + } + } + }, + "upb@0.0.0-20220923-a547704": { + "name": "upb", + "version": "0.0.0-20220923-a547704", + "key": "upb@0.0.0-20220923-a547704", + "repoName": "upb", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_proto": "rules_proto@5.3.0-21.7", + "com_google_protobuf": "protobuf@21.7", + "com_google_absl": "abseil-cpp@20211102.0", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/protocolbuffers/upb/archive/a5477045acaa34586420942098f5fecd3570f577.tar.gz" + ], + "integrity": "sha256-z39x6v+QskwaKLSWRan/A6mmwecTQpHOcJActj5zZLU=", + "strip_prefix": "upb-a5477045acaa34586420942098f5fecd3570f577", + "remote_patches": { + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/patches/module_dot_bazel.patch": "sha256-wH4mNS6ZYy+8uC0HoAft/c7SDsq2Kxf+J8dUakXhaB0=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_jvm_external@4.4.2": { + "name": "rules_jvm_external", + "version": "4.4.2", + "key": "rules_jvm_external@4.4.2", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@4.4.2", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@4.4.2", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.cloud:google-cloud-core:1.93.10", + "com.google.cloud:google-cloud-storage:1.113.4", + "com.google.code.gson:gson:2.9.0", + "org.apache.maven:maven-artifact:3.8.6", + "software.amazon.awssdk:s3:2.17.183" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "io_bazel_stardoc": "stardoc@0.5.1", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/4.4.2.zip" + ], + "integrity": "sha256-c1YC9QgT6y6pPKP15DsZWb2AshO4NqB6YqKddXZwt3s=", + "strip_prefix": "rules_jvm_external-4.4.2", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "googletest@1.11.0": { + "name": "googletest", + "version": "1.11.0", + "key": "googletest@1.11.0", + "repoName": "googletest", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "com_google_absl": "abseil-cpp@20211102.0", + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz" + ], + "integrity": "sha256-tIcL8SH/d5W6INILzdhie44Ijy0dqymaAxwQNO3ck9U=", + "strip_prefix": "googletest-release-1.11.0", + "remote_patches": { + "https://bcr.bazel.build/modules/googletest/1.11.0/patches/module_dot_bazel.patch": "sha256-HuahEdI/n8KCI071sN3CEziX+7qP/Ec77IWayYunLP0=" + }, + "remote_patch_strip": 0 + } + } + }, + "stardoc@0.5.1": { + "name": "stardoc", + "version": "0.5.1", + "key": "stardoc@0.5.1", + "repoName": "stardoc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.3.0", + "rules_java": "rules_java@7.4.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "urls": [ + "https://github.com/bazelbuild/stardoc/releases/download/0.5.1/stardoc-0.5.1.tar.gz" + ], + "integrity": "sha256-qoFNrgrEALurLoiB+ZFcb0fElmS/CHxAmhX5BDjSwj4=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/stardoc/0.5.1/patches/module_dot_bazel.patch": "sha256-UAULCuTpJE7SG0YrR9XLjMfxMRmbP+za3uW9ONZ5rjI=" + }, + "remote_patch_strip": 0 + } + } + } + }, + "moduleExtensions": { + "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_apple_cc": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": {} + }, + "local_config_apple_cc_toolchains": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf_toolchains", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "PHpT2yqMGms2U4L3E/aZ+WcQalmZWm+ILdP3yiLsDhA=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_cc": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf", + "attributes": {} + }, + "local_config_cc_toolchains": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf_toolchains", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [ + [ + "bazel_tools", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { + "general": { + "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_xcode": { + "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", + "ruleClassName": "xcode_autoconf", + "attributes": { + "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", + "remote_xcode": "" + } + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { + "general": { + "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_sh": { + "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", + "ruleClassName": "sh_config", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@rules_java~//java:extensions.bzl%toolchains": { + "general": { + "bzlTransitiveDigest": "tJHbmWnq7m+9eUBnUdv7jZziQ26FmcGL9C5/hU3Q9UQ=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "remotejdk21_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "e8260516de8b60661422a725f1df2c36ef888f6fb35393566b00e7325db3d04e", + "strip_prefix": "zulu21.32.17-ca-jdk21.0.2-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" + ] + } + }, + "remote_java_tools_windows": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "fe2f88169696d6c6fc6e90ba61bb46be7d0ae3693cbafdf336041bf56679e8d1", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.4/java_tools_windows-v13.4.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.4/java_tools_windows-v13.4.zip" + ] + } + }, + "remotejdk11_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" + ] + } + }, + "remotejdk11_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" + } + }, + "remotejdk11_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" + ] + } + }, + "remotejdk11_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", + "strip_prefix": "jdk-11.0.13+8", + "urls": [ + "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" + ] + } + }, + "remotejdk17_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "3ad8fe288eb57d975c2786ae453a036aa46e47ab2ac3d81538ebae2a54d3c025", + "strip_prefix": "zulu21.32.17-ca-jdk21.0.2-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" + ] + } + }, + "remotejdk11_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk21_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "5ad730fbee6bb49bfff10bf39e84392e728d89103d3474a7e5def0fd134b300a", + "strip_prefix": "zulu21.32.17-ca-jdk21.0.2-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_x64.tar.gz" + ] + } + }, + "remote_java_tools_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "ba10f09a138cf185d04cbc807d67a3da42ab13d618c5d1ce20d776e199c33a39", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.4/java_tools_linux-v13.4.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.4/java_tools_linux-v13.4.zip" + ] + } + }, + "remotejdk21_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "f7cc15ca17295e69c907402dfe8db240db446e75d3b150da7bf67243cded93de", + "strip_prefix": "zulu21.32.17-ca-jdk21.0.2-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-win_x64.zip" + ] + } + }, + "remotejdk21_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "ce7df1af5d44a9f455617c4b8891443fbe3e4b269c777d8b82ed66f77167cfe0", + "strip_prefix": "zulu21.32.17-ca-jdk21.0.2-linux_aarch64", + "urls": [ + "https://cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz", + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.32.17-ca-jdk21.0.2-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk11_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk17_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk17_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" + ] + } + }, + "remote_java_tools_darwin_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "076a7e198ad077f8c7d997986ef5102427fae6bbfce7a7852d2e080ed8767528", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.4/java_tools_darwin_arm64-v13.4.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.4/java_tools_darwin_arm64-v13.4.zip" + ] + } + }, + "remotejdk17_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk21_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" + } + }, + "local_jdk": { + "bzlFile": "@@rules_java~//toolchains:local_java_repository.bzl", + "ruleClassName": "_local_java_repository_rule", + "attributes": { + "java_home": "", + "version": "", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" + } + }, + "remote_java_tools_darwin_x86_64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "4523aec4d09c587091a2dae6f5c9bc6922c220f3b6030e5aba9c8f015913cc65", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.4/java_tools_darwin_x86_64-v13.4.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.4/java_tools_darwin_x86_64-v13.4.zip" + ] + } + }, + "remote_java_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "e025fd260ac39b47c111f5212d64ec0d00d85dec16e49368aae82fc626a940cf", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.4/java_tools-v13.4.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.4/java_tools-v13.4.zip" + ] + } + }, + "remotejdk17_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk17_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk11_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk21_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_java~", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_java~", + "remote_java_tools", + "rules_java~~toolchains~remote_java_tools" + ] + ] + } + } + } +}
diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..f96b8c2 --- /dev/null +++ b/WORKSPACE
@@ -0,0 +1,51 @@ +workspace(name = "nearby-rust") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "bazel_skylib", + sha256 = "66ffd9315665bfaafc96b52278f57c7e2dd09f5ede279ea6d39b2be471e7e3aa", + urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.2/bazel-skylib-1.4.2.tar.gz"], +) + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") + +bazel_skylib_workspace() + +http_archive( + name = "rules_rust", + integrity = "sha256-JLN47ZcAbx9wEr5Jiib4HduZATGLiDgK7oUi/fvotzU=", + urls = ["https://github.com/bazelbuild/rules_rust/releases/download/0.42.1/rules_rust-v0.42.1.tar.gz"], +) + +load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_repository", "render_config", "splicing_config") +load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains") + +rules_rust_dependencies() + +rust_register_toolchains( + edition = "2021", + versions = [ + "1.77.1", + ], +) + +crates_repository( + name = "crate_index", + cargo_lockfile = "//:bazel_placeholder/Cargo.lock", + lockfile = "//:bazel_placeholder/Cargo.Bazel.lock", + manifests = [ + "//:bazel_placeholder/Cargo.toml", + ], +) + +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +local_repository( + name = "absl", + path = "third_party/abseil-cpp", +) + +load("@crate_index//:defs.bzl", "crate_repositories") + +crate_repositories()
diff --git a/bazel_placeholder/Cargo.Bazel.lock b/bazel_placeholder/Cargo.Bazel.lock new file mode 100644 index 0000000..61c368f --- /dev/null +++ b/bazel_placeholder/Cargo.Bazel.lock
@@ -0,0 +1,4318 @@ +{ + "checksum": "8252b2836647756486e1f6f409834897441b4ab161b9310b2c30f0a2ecf13ef6", + "crates": { + "aead 0.5.2": { + "name": "aead", + "version": "0.5.2", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/aead/0.5.2/download", + "sha256": "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "aead", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "aead", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "rand_core" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + }, + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.5.2" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "aes 0.8.4": { + "name": "aes", + "version": "0.8.4", + "package_url": "https://github.com/RustCrypto/block-ciphers", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/aes/0.8.4/download", + "sha256": "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "aes", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "aes", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "cipher 0.4.4", + "target": "cipher" + } + ], + "selects": { + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + { + "id": "cpufeatures 0.2.12", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2021", + "version": "0.8.4" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "aes-gcm 0.10.3": { + "name": "aes-gcm", + "version": "0.10.3", + "package_url": "https://github.com/RustCrypto/AEADs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/aes-gcm/0.10.3/download", + "sha256": "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" + } + }, + "targets": [ + { + "Library": { + "crate_name": "aes_gcm", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "aes_gcm", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "aes" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "aead 0.5.2", + "target": "aead" + }, + { + "id": "aes 0.8.4", + "target": "aes" + }, + { + "id": "cipher 0.4.4", + "target": "cipher" + }, + { + "id": "ctr 0.9.2", + "target": "ctr" + }, + { + "id": "ghash 0.5.1", + "target": "ghash" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.10.3" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "aes-gcm-siv 0.11.1": { + "name": "aes-gcm-siv", + "version": "0.11.1", + "package_url": "https://github.com/RustCrypto/AEADs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/aes-gcm-siv/0.11.1/download", + "sha256": "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "aes_gcm_siv", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "aes_gcm_siv", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "aes" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "aead 0.5.2", + "target": "aead" + }, + { + "id": "aes 0.8.4", + "target": "aes" + }, + { + "id": "cipher 0.4.4", + "target": "cipher" + }, + { + "id": "ctr 0.9.2", + "target": "ctr" + }, + { + "id": "polyval 0.6.2", + "target": "polyval" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.11.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "base16ct 0.2.0": { + "name": "base16ct", + "version": "0.2.0", + "package_url": "https://github.com/RustCrypto/formats/tree/master/base16ct", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/base16ct/0.2.0/download", + "sha256": "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + } + }, + "targets": [ + { + "Library": { + "crate_name": "base16ct", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "base16ct", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.2.0" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "block-buffer 0.10.4": { + "name": "block-buffer", + "version": "0.10.4", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/block-buffer/0.10.4/download", + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" + } + }, + "targets": [ + { + "Library": { + "crate_name": "block_buffer", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "block_buffer", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.10.4" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "block-padding 0.3.3": { + "name": "block-padding", + "version": "0.3.3", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/block-padding/0.3.3/download", + "sha256": "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" + } + }, + "targets": [ + { + "Library": { + "crate_name": "block_padding", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "block_padding", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.3.3" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "cbc 0.1.2": { + "name": "cbc", + "version": "0.1.2", + "package_url": "https://github.com/RustCrypto/block-modes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cbc/0.1.2/download", + "sha256": "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cbc", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "cbc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "block-padding" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "cipher 0.4.4", + "target": "cipher" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.1.2" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "cfg-if 1.0.0": { + "name": "cfg-if", + "version": "1.0.0", + "package_url": "https://github.com/alexcrichton/cfg-if", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cfg-if/1.0.0/download", + "sha256": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cfg_if", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "cfg_if", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "1.0.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "cipher 0.4.4": { + "name": "cipher", + "version": "0.4.4", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cipher/0.4.4/download", + "sha256": "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cipher", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "cipher", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "block-padding" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + }, + { + "id": "inout 0.1.3", + "target": "inout" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.4.4" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "const-oid 0.9.6": { + "name": "const-oid", + "version": "0.9.6", + "package_url": "https://github.com/RustCrypto/formats/tree/master/const-oid", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/const-oid/0.9.6/download", + "sha256": "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "const_oid", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "const_oid", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.9.6" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "cpufeatures 0.2.12": { + "name": "cpufeatures", + "version": "0.2.12", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cpufeatures/0.2.12/download", + "sha256": "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cpufeatures", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "cpufeatures", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "aarch64-linux-android": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ], + "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ], + "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ], + "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ] + } + }, + "edition": "2018", + "version": "0.2.12" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "crypto-bigint 0.5.5": { + "name": "crypto-bigint", + "version": "0.5.5", + "package_url": "https://github.com/RustCrypto/crypto-bigint", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crypto-bigint/0.5.5/download", + "sha256": "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crypto_bigint", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "crypto_bigint", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "generic-array", + "rand_core", + "zeroize" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.5.5" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "crypto-common 0.1.6": { + "name": "crypto-common", + "version": "0.1.6", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crypto-common/0.1.6/download", + "sha256": "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crypto_common", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "crypto_common", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "rand_core" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "typenum 1.17.0", + "target": "typenum" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.1.6" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ctr 0.9.2": { + "name": "ctr", + "version": "0.9.2", + "package_url": "https://github.com/RustCrypto/block-modes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ctr/0.9.2/download", + "sha256": "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ctr", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ctr", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cipher 0.4.4", + "target": "cipher" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.9.2" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "curve25519-dalek 4.1.2": { + "name": "curve25519-dalek", + "version": "4.1.2", + "package_url": "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/curve25519-dalek/4.1.2/download", + "sha256": "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" + } + }, + "targets": [ + { + "Library": { + "crate_name": "curve25519_dalek", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "curve25519_dalek", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "digest" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "curve25519-dalek 4.1.2", + "target": "build_script_build" + }, + { + "id": "digest 0.10.7", + "target": "digest" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": { + "cfg(curve25519_dalek_backend = \"fiat\")": [ + { + "id": "fiat-crypto 0.2.7", + "target": "fiat_crypto" + } + ], + "cfg(target_arch = \"x86_64\")": [ + { + "id": "cpufeatures 0.2.12", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2021", + "proc_macro_deps": { + "common": [], + "selects": { + "cfg(all(not(curve25519_dalek_backend = \"fiat\"), not(curve25519_dalek_backend = \"serial\"), target_arch = \"x86_64\"))": [ + { + "id": "curve25519-dalek-derive 0.1.1", + "target": "curve25519_dalek_derive" + } + ] + } + }, + "version": "4.1.2" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "platforms 3.4.0", + "target": "platforms" + }, + { + "id": "rustc_version 0.4.0", + "target": "rustc_version" + } + ], + "selects": {} + } + }, + "license": "BSD-3-Clause", + "license_ids": [ + "BSD-3-Clause" + ], + "license_file": "LICENSE" + }, + "curve25519-dalek-derive 0.1.1": { + "name": "curve25519-dalek-derive", + "version": "0.1.1", + "package_url": "https://github.com/dalek-cryptography/curve25519-dalek", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/curve25519-dalek-derive/0.1.1/download", + "sha256": "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "curve25519_dalek_derive", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "curve25519_dalek_derive", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.81", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.59", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.1.1" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "der 0.7.9": { + "name": "der", + "version": "0.7.9", + "package_url": "https://github.com/RustCrypto/formats/tree/master/der", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/der/0.7.9/download", + "sha256": "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "der", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "der", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "oid", + "zeroize" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "const-oid 0.9.6", + "target": "const_oid" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.7.9" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "digest 0.10.7": { + "name": "digest", + "version": "0.10.7", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/digest/0.10.7/download", + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" + } + }, + "targets": [ + { + "Library": { + "crate_name": "digest", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "digest", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "block-buffer", + "core-api", + "default", + "mac", + "subtle" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "block-buffer 0.10.4", + "target": "block_buffer" + }, + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.10.7" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ed25519 2.2.3": { + "name": "ed25519", + "version": "2.2.3", + "package_url": "https://github.com/RustCrypto/signatures/tree/master/ed25519", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ed25519/2.2.3/download", + "sha256": "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ed25519", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ed25519", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "signature 2.2.0", + "target": "signature" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.2.3" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ed25519-dalek 2.1.1": { + "name": "ed25519-dalek", + "version": "2.1.1", + "package_url": "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ed25519-dalek/2.1.1/download", + "sha256": "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ed25519_dalek", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ed25519_dalek", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "rand_core" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "curve25519-dalek 4.1.2", + "target": "curve25519_dalek" + }, + { + "id": "ed25519 2.2.3", + "target": "ed25519" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "sha2 0.10.8", + "target": "sha2" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.1.1" + }, + "license": "BSD-3-Clause", + "license_ids": [ + "BSD-3-Clause" + ], + "license_file": "LICENSE" + }, + "elliptic-curve 0.13.8": { + "name": "elliptic-curve", + "version": "0.13.8", + "package_url": "https://github.com/RustCrypto/traits/tree/master/elliptic-curve", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/elliptic-curve/0.13.8/download", + "sha256": "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" + } + }, + "targets": [ + { + "Library": { + "crate_name": "elliptic_curve", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "elliptic_curve", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "arithmetic", + "digest", + "ecdh", + "ff", + "group", + "hazmat", + "sec1" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "base16ct 0.2.0", + "target": "base16ct" + }, + { + "id": "crypto-bigint 0.5.5", + "target": "crypto_bigint" + }, + { + "id": "digest 0.10.7", + "target": "digest" + }, + { + "id": "ff 0.13.0", + "target": "ff" + }, + { + "id": "generic-array 0.14.7", + "target": "generic_array" + }, + { + "id": "group 0.13.0", + "target": "group" + }, + { + "id": "hkdf 0.12.4", + "target": "hkdf" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "sec1 0.7.3", + "target": "sec1" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.13.8" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ff 0.13.0": { + "name": "ff", + "version": "0.13.0", + "package_url": "https://github.com/zkcrypto/ff", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ff/0.13.0/download", + "sha256": "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ff", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ff", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.13.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "fiat-crypto 0.2.7": { + "name": "fiat-crypto", + "version": "0.2.7", + "package_url": "https://github.com/mit-plv/fiat-crypto", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/fiat-crypto/0.2.7/download", + "sha256": "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "fiat_crypto", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "fiat_crypto", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.2.7" + }, + "license": "MIT OR Apache-2.0 OR BSD-1-Clause", + "license_ids": [ + "Apache-2.0", + "BSD-1-Clause", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "generic-array 0.14.7": { + "name": "generic-array", + "version": "0.14.7", + "package_url": "https://github.com/fizyk20/generic-array.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/generic-array/0.14.7/download", + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "generic_array", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "generic_array", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "more_lengths", + "zeroize" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "build_script_build" + }, + { + "id": "typenum 1.17.0", + "target": "typenum" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.14.7" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "version_check 0.9.4", + "target": "version_check" + } + ], + "selects": {} + } + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "getrandom 0.2.14": { + "name": "getrandom", + "version": "0.2.14", + "package_url": "https://github.com/rust-random/getrandom", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/getrandom/0.2.14/download", + "sha256": "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" + } + }, + "targets": [ + { + "Library": { + "crate_name": "getrandom", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "getrandom", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + } + ], + "selects": { + "cfg(target_os = \"wasi\")": [ + { + "id": "wasi 0.11.0+wasi-snapshot-preview1", + "target": "wasi" + } + ], + "cfg(unix)": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ] + } + }, + "edition": "2018", + "version": "0.2.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ghash 0.5.1": { + "name": "ghash", + "version": "0.5.1", + "package_url": "https://github.com/RustCrypto/universal-hashes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ghash/0.5.1/download", + "sha256": "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ghash", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ghash", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "opaque-debug 0.3.1", + "target": "opaque_debug" + }, + { + "id": "polyval 0.6.2", + "target": "polyval" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.5.1" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "group 0.13.0": { + "name": "group", + "version": "0.13.0", + "package_url": "https://github.com/zkcrypto/group", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/group/0.13.0/download", + "sha256": "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" + } + }, + "targets": [ + { + "Library": { + "crate_name": "group", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "group", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "ff 0.13.0", + "target": "ff" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.13.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "heck 0.4.1": { + "name": "heck", + "version": "0.4.1", + "package_url": "https://github.com/withoutboats/heck", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/heck/0.4.1/download", + "sha256": "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "heck", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "heck", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default" + ], + "selects": {} + }, + "edition": "2018", + "version": "0.4.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "hkdf 0.12.4": { + "name": "hkdf", + "version": "0.12.4", + "package_url": "https://github.com/RustCrypto/KDFs/", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/hkdf/0.12.4/download", + "sha256": "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "hkdf", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "hkdf", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "hmac 0.12.1", + "target": "hmac" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.12.4" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "hmac 0.12.1": { + "name": "hmac", + "version": "0.12.1", + "package_url": "https://github.com/RustCrypto/MACs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/hmac/0.12.1/download", + "sha256": "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" + } + }, + "targets": [ + { + "Library": { + "crate_name": "hmac", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "hmac", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "digest 0.10.7", + "target": "digest" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.12.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "inout 0.1.3": { + "name": "inout", + "version": "0.1.3", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/inout/0.1.3/download", + "sha256": "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" + } + }, + "targets": [ + { + "Library": { + "crate_name": "inout", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "inout", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "block-padding" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "block-padding 0.3.3", + "target": "block_padding" + }, + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.1.3" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "lazy_static 1.4.0": { + "name": "lazy_static", + "version": "1.4.0", + "package_url": "https://github.com/rust-lang-nursery/lazy-static.rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lazy_static/1.4.0/download", + "sha256": "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lazy_static", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "lazy_static", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "spin", + "spin_no_std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "spin 0.5.2", + "target": "spin" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "1.4.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "libc 0.2.153": { + "name": "libc", + "version": "0.2.153", + "package_url": "https://github.com/rust-lang/libc", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/libc/0.2.153/download", + "sha256": "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + } + }, + "targets": [ + { + "Library": { + "crate_name": "libc", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "libc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [], + "selects": { + "aarch64-apple-darwin": [ + "default", + "std" + ], + "aarch64-apple-ios": [ + "default", + "std" + ], + "aarch64-apple-ios-sim": [ + "default", + "std" + ], + "aarch64-linux-android": [ + "default", + "std" + ], + "aarch64-unknown-linux-gnu": [ + "default", + "std" + ], + "aarch64-unknown-nixos-gnu": [ + "default", + "std" + ] + } + }, + "deps": { + "common": [ + { + "id": "libc 0.2.153", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.2.153" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "memchr 2.7.2": { + "name": "memchr", + "version": "2.7.2", + "package_url": "https://github.com/BurntSushi/memchr", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/memchr/2.7.2/download", + "sha256": "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "memchr", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "memchr", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "2.7.2" + }, + "license": "Unlicense OR MIT", + "license_ids": [ + "MIT", + "Unlicense" + ], + "license_file": "LICENSE-MIT" + }, + "minimal-lexical 0.2.1": { + "name": "minimal-lexical", + "version": "0.2.1", + "package_url": "https://github.com/Alexhuszagh/minimal-lexical", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/minimal-lexical/0.2.1/download", + "sha256": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "minimal_lexical", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "minimal_lexical", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.2.1" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "nom 7.1.3": { + "name": "nom", + "version": "7.1.3", + "package_url": "https://github.com/Geal/nom", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/nom/7.1.3/download", + "sha256": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "nom", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "nom", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "memchr 2.7.2", + "target": "memchr" + }, + { + "id": "minimal-lexical 0.2.1", + "target": "minimal_lexical" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "7.1.3" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "opaque-debug 0.3.1": { + "name": "opaque-debug", + "version": "0.3.1", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/opaque-debug/0.3.1/download", + "sha256": "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + } + }, + "targets": [ + { + "Library": { + "crate_name": "opaque_debug", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "opaque_debug", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.3.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "p256 0.13.2": { + "name": "p256", + "version": "0.13.2", + "package_url": "https://github.com/RustCrypto/elliptic-curves/tree/master/p256", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/p256/0.13.2/download", + "sha256": "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "p256", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "p256", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "arithmetic", + "ecdh" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "elliptic-curve 0.13.8", + "target": "elliptic_curve" + }, + { + "id": "primeorder 0.13.6", + "target": "primeorder" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.13.2" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "place_holder 0.1.0": { + "name": "place_holder", + "version": "0.1.0", + "package_url": null, + "repository": null, + "targets": [ + { + "Library": { + "crate_name": "place_holder", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "place_holder", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "aead 0.5.2", + "target": "aead" + }, + { + "id": "aes 0.8.4", + "target": "aes" + }, + { + "id": "aes-gcm 0.10.3", + "target": "aes_gcm" + }, + { + "id": "aes-gcm-siv 0.11.1", + "target": "aes_gcm_siv" + }, + { + "id": "cbc 0.1.2", + "target": "cbc" + }, + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "ctr 0.9.2", + "target": "ctr" + }, + { + "id": "ed25519-dalek 2.1.1", + "target": "ed25519_dalek" + }, + { + "id": "hkdf 0.12.4", + "target": "hkdf" + }, + { + "id": "hmac 0.12.1", + "target": "hmac" + }, + { + "id": "lazy_static 1.4.0", + "target": "lazy_static" + }, + { + "id": "nom 7.1.3", + "target": "nom" + }, + { + "id": "p256 0.13.2", + "target": "p256" + }, + { + "id": "rand 0.8.5", + "target": "rand" + }, + { + "id": "rand_chacha 0.3.1", + "target": "rand_chacha" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + }, + { + "id": "sec1 0.7.3", + "target": "sec1" + }, + { + "id": "sha2 0.10.8", + "target": "sha2" + }, + { + "id": "strum 0.25.0", + "target": "strum" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + }, + { + "id": "thiserror 1.0.58", + "target": "thiserror" + }, + { + "id": "tinyvec 1.6.0", + "target": "tinyvec" + }, + { + "id": "x25519-dalek 2.0.1", + "target": "x25519_dalek" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "strum_macros 0.25.3", + "target": "strum_macros" + } + ], + "selects": {} + }, + "version": "0.1.0" + }, + "license": null, + "license_ids": [], + "license_file": null + }, + "platforms 3.4.0": { + "name": "platforms", + "version": "3.4.0", + "package_url": "https://github.com/rustsec/rustsec/tree/main/platforms", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/platforms/3.4.0/download", + "sha256": "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "platforms", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "platforms", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2018", + "version": "3.4.0" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "polyval 0.6.2": { + "name": "polyval", + "version": "0.6.2", + "package_url": "https://github.com/RustCrypto/universal-hashes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/polyval/0.6.2/download", + "sha256": "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" + } + }, + "targets": [ + { + "Library": { + "crate_name": "polyval", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "polyval", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "opaque-debug 0.3.1", + "target": "opaque_debug" + }, + { + "id": "universal-hash 0.5.1", + "target": "universal_hash" + } + ], + "selects": { + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + { + "id": "cpufeatures 0.2.12", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2021", + "version": "0.6.2" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ppv-lite86 0.2.17": { + "name": "ppv-lite86", + "version": "0.2.17", + "package_url": "https://github.com/cryptocorrosion/cryptocorrosion", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ppv-lite86/0.2.17/download", + "sha256": "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ppv_lite86", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ppv_lite86", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "simd", + "std" + ], + "selects": {} + }, + "edition": "2018", + "version": "0.2.17" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "primeorder 0.13.6": { + "name": "primeorder", + "version": "0.13.6", + "package_url": "https://github.com/RustCrypto/elliptic-curves/tree/master/primeorder", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/primeorder/0.13.6/download", + "sha256": "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" + } + }, + "targets": [ + { + "Library": { + "crate_name": "primeorder", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "primeorder", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "elliptic-curve 0.13.8", + "target": "elliptic_curve" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.13.6" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "proc-macro2 1.0.81": { + "name": "proc-macro2", + "version": "1.0.81", + "package_url": "https://github.com/dtolnay/proc-macro2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/proc-macro2/1.0.81/download", + "sha256": "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" + } + }, + "targets": [ + { + "Library": { + "crate_name": "proc_macro2", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "proc_macro2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "proc-macro" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.81", + "target": "build_script_build" + }, + { + "id": "unicode-ident 1.0.12", + "target": "unicode_ident" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.81" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "quote 1.0.36": { + "name": "quote", + "version": "1.0.36", + "package_url": "https://github.com/dtolnay/quote", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/quote/1.0.36/download", + "sha256": "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "quote", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "quote", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "proc-macro" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.81", + "target": "proc_macro2" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.36" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rand 0.8.5": { + "name": "rand", + "version": "0.8.5", + "package_url": "https://github.com/rust-random/rand", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rand/0.8.5/download", + "sha256": "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rand", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rand", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "getrandom", + "libc", + "rand_chacha", + "std", + "std_rng" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "rand_chacha 0.3.1", + "target": "rand_chacha" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + } + ], + "selects": { + "cfg(unix)": [ + { + "id": "libc 0.2.153", + "target": "libc" + } + ] + } + }, + "edition": "2018", + "version": "0.8.5" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rand_chacha 0.3.1": { + "name": "rand_chacha", + "version": "0.3.1", + "package_url": "https://github.com/rust-random/rand", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rand_chacha/0.3.1/download", + "sha256": "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rand_chacha", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rand_chacha", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "ppv-lite86 0.2.17", + "target": "ppv_lite86" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.3.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rand_core 0.6.4": { + "name": "rand_core", + "version": "0.6.4", + "package_url": "https://github.com/rust-random/rand", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rand_core/0.6.4/download", + "sha256": "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rand_core", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rand_core", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "getrandom", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "getrandom 0.2.14", + "target": "getrandom" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.6.4" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rustc_version 0.4.0": { + "name": "rustc_version", + "version": "0.4.0", + "package_url": "https://github.com/Kimundi/rustc-version-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rustc_version/0.4.0/download", + "sha256": "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rustc_version", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rustc_version", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "semver 1.0.22", + "target": "semver" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.4.0" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rustversion 1.0.15": { + "name": "rustversion", + "version": "1.0.15", + "package_url": "https://github.com/dtolnay/rustversion", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rustversion/1.0.15/download", + "sha256": "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "rustversion", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build/build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rustversion", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "rustversion 1.0.15", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.15" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "sec1 0.7.3": { + "name": "sec1", + "version": "0.7.3", + "package_url": "https://github.com/RustCrypto/formats/tree/master/sec1", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/sec1/0.7.3/download", + "sha256": "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" + } + }, + "targets": [ + { + "Library": { + "crate_name": "sec1", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "sec1", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "der", + "point", + "subtle", + "zeroize" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "base16ct 0.2.0", + "target": "base16ct" + }, + { + "id": "der 0.7.9", + "target": "der" + }, + { + "id": "generic-array 0.14.7", + "target": "generic_array" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + }, + { + "id": "zeroize 1.7.0", + "target": "zeroize" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.7.3" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "semver 1.0.22": { + "name": "semver", + "version": "1.0.22", + "package_url": "https://github.com/dtolnay/semver", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/semver/1.0.22/download", + "sha256": "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + } + }, + "targets": [ + { + "Library": { + "crate_name": "semver", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "semver", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "semver 1.0.22", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.22" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "sha2 0.10.8": { + "name": "sha2", + "version": "0.10.8", + "package_url": "https://github.com/RustCrypto/hashes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/sha2/0.10.8/download", + "sha256": "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "sha2", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "sha2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "digest 0.10.7", + "target": "digest" + } + ], + "selects": { + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + { + "id": "cpufeatures 0.2.12", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2018", + "version": "0.10.8" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "signature 2.2.0": { + "name": "signature", + "version": "2.2.0", + "package_url": "https://github.com/RustCrypto/traits/tree/master/signature", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/signature/2.2.0/download", + "sha256": "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + } + }, + "targets": [ + { + "Library": { + "crate_name": "signature", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "signature", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "2.2.0" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "spin 0.5.2": { + "name": "spin", + "version": "0.5.2", + "package_url": "https://github.com/mvdnes/spin-rs.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/spin/0.5.2/download", + "sha256": "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "spin", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "spin", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "0.5.2" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "strum 0.25.0": { + "name": "strum", + "version": "0.25.0", + "package_url": "https://github.com/Peternator7/strum", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/strum/0.25.0/download", + "sha256": "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + } + }, + "targets": [ + { + "Library": { + "crate_name": "strum", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "strum", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.25.0" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "strum_macros 0.25.3": { + "name": "strum_macros", + "version": "0.25.3", + "package_url": "https://github.com/Peternator7/strum", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/strum_macros/0.25.3/download", + "sha256": "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "strum_macros", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "strum_macros", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "heck 0.4.1", + "target": "heck" + }, + { + "id": "proc-macro2 1.0.81", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.59", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2018", + "proc_macro_deps": { + "common": [ + { + "id": "rustversion 1.0.15", + "target": "rustversion" + } + ], + "selects": {} + }, + "version": "0.25.3" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "subtle 2.5.0": { + "name": "subtle", + "version": "2.5.0", + "package_url": "https://github.com/dalek-cryptography/subtle", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/subtle/2.5.0/download", + "sha256": "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + } + }, + "targets": [ + { + "Library": { + "crate_name": "subtle", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "subtle", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "i128" + ], + "selects": {} + }, + "edition": "2018", + "version": "2.5.0" + }, + "license": "BSD-3-Clause", + "license_ids": [ + "BSD-3-Clause" + ], + "license_file": "LICENSE" + }, + "syn 2.0.59": { + "name": "syn", + "version": "2.0.59", + "package_url": "https://github.com/dtolnay/syn", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/syn/2.0.59/download", + "sha256": "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "syn", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "syn", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "clone-impls", + "default", + "derive", + "extra-traits", + "parsing", + "printing", + "proc-macro" + ], + "selects": { + "x86_64-apple-darwin": [ + "full" + ], + "x86_64-apple-ios": [ + "full" + ], + "x86_64-fuchsia": [ + "full" + ], + "x86_64-linux-android": [ + "full" + ], + "x86_64-pc-windows-msvc": [ + "full" + ], + "x86_64-unknown-freebsd": [ + "full" + ], + "x86_64-unknown-linux-gnu": [ + "full" + ], + "x86_64-unknown-nixos-gnu": [ + "full" + ], + "x86_64-unknown-none": [ + "full" + ] + } + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.81", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "unicode-ident 1.0.12", + "target": "unicode_ident" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.0.59" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "thiserror 1.0.58": { + "name": "thiserror", + "version": "1.0.58", + "package_url": "https://github.com/dtolnay/thiserror", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/thiserror/1.0.58/download", + "sha256": "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" + } + }, + "targets": [ + { + "Library": { + "crate_name": "thiserror", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "thiserror", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "thiserror 1.0.58", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "thiserror-impl 1.0.58", + "target": "thiserror_impl" + } + ], + "selects": {} + }, + "version": "1.0.58" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "thiserror-impl 1.0.58": { + "name": "thiserror-impl", + "version": "1.0.58", + "package_url": "https://github.com/dtolnay/thiserror", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/thiserror-impl/1.0.58/download", + "sha256": "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "thiserror_impl", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "thiserror_impl", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.81", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.59", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.58" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "tinyvec 1.6.0": { + "name": "tinyvec", + "version": "1.6.0", + "package_url": "https://github.com/Lokathor/tinyvec", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/tinyvec/1.6.0/download", + "sha256": "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" + } + }, + "targets": [ + { + "Library": { + "crate_name": "tinyvec", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "tinyvec", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "rustc_1_40", + "rustc_1_55" + ], + "selects": {} + }, + "edition": "2018", + "version": "1.6.0" + }, + "license": "Zlib OR Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT", + "Zlib" + ], + "license_file": "LICENSE-APACHE.md" + }, + "typenum 1.17.0": { + "name": "typenum", + "version": "1.17.0", + "package_url": "https://github.com/paholg/typenum", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/typenum/1.17.0/download", + "sha256": "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + } + }, + "targets": [ + { + "Library": { + "crate_name": "typenum", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_main", + "crate_root": "build/main.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "typenum", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "typenum 1.17.0", + "target": "build_script_main" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.17.0" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE" + }, + "unicode-ident 1.0.12": { + "name": "unicode-ident", + "version": "1.0.12", + "package_url": "https://github.com/dtolnay/unicode-ident", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/unicode-ident/1.0.12/download", + "sha256": "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "unicode_ident", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "unicode_ident", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "1.0.12" + }, + "license": "(MIT OR Apache-2.0) AND Unicode-DFS-2016", + "license_ids": [ + "Apache-2.0", + "MIT", + "Unicode-DFS-2016" + ], + "license_file": "LICENSE-APACHE" + }, + "universal-hash 0.5.1": { + "name": "universal-hash", + "version": "0.5.1", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/universal-hash/0.5.1/download", + "sha256": "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" + } + }, + "targets": [ + { + "Library": { + "crate_name": "universal_hash", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "universal_hash", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + }, + { + "id": "subtle 2.5.0", + "target": "subtle" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.5.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "version_check 0.9.4": { + "name": "version_check", + "version": "0.9.4", + "package_url": "https://github.com/SergioBenitez/version_check", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/version_check/0.9.4/download", + "sha256": "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "version_check", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "version_check", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "0.9.4" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "wasi 0.11.0+wasi-snapshot-preview1": { + "name": "wasi", + "version": "0.11.0+wasi-snapshot-preview1", + "package_url": "https://github.com/bytecodealliance/wasi", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasi/0.11.0+wasi-snapshot-preview1/download", + "sha256": "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + } + }, + "targets": [ + { + "Library": { + "crate_name": "wasi", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasi", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.11.0+wasi-snapshot-preview1" + }, + "license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "x25519-dalek 2.0.1": { + "name": "x25519-dalek", + "version": "2.0.1", + "package_url": "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/x25519-dalek", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/x25519-dalek/2.0.1/download", + "sha256": "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" + } + }, + "targets": [ + { + "Library": { + "crate_name": "x25519_dalek", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "x25519_dalek", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "curve25519-dalek 4.1.2", + "target": "curve25519_dalek" + }, + { + "id": "rand_core 0.6.4", + "target": "rand_core" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.0.1" + }, + "license": "BSD-3-Clause", + "license_ids": [ + "BSD-3-Clause" + ], + "license_file": "LICENSE" + }, + "zeroize 1.7.0": { + "name": "zeroize", + "version": "1.7.0", + "package_url": "https://github.com/RustCrypto/utils/tree/master/zeroize", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zeroize/1.7.0/download", + "sha256": "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zeroize", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "zeroize", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "1.7.0" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + } + }, + "binary_crates": [], + "workspace_members": { + "place_holder 0.1.0": "" + }, + "conditions": { + "aarch64-apple-darwin": [ + "aarch64-apple-darwin" + ], + "aarch64-apple-ios": [ + "aarch64-apple-ios" + ], + "aarch64-apple-ios-sim": [ + "aarch64-apple-ios-sim" + ], + "aarch64-fuchsia": [ + "aarch64-fuchsia" + ], + "aarch64-linux-android": [ + "aarch64-linux-android" + ], + "aarch64-pc-windows-msvc": [ + "aarch64-pc-windows-msvc" + ], + "aarch64-unknown-linux-gnu": [ + "aarch64-unknown-linux-gnu" + ], + "aarch64-unknown-nixos-gnu": [ + "aarch64-unknown-nixos-gnu" + ], + "aarch64-unknown-nto-qnx710": [ + "aarch64-unknown-nto-qnx710" + ], + "arm-unknown-linux-gnueabi": [ + "arm-unknown-linux-gnueabi" + ], + "armv7-linux-androideabi": [ + "armv7-linux-androideabi" + ], + "armv7-unknown-linux-gnueabi": [ + "armv7-unknown-linux-gnueabi" + ], + "cfg(all(not(curve25519_dalek_backend = \"fiat\"), not(curve25519_dalek_backend = \"serial\"), target_arch = \"x86_64\"))": [ + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu", + "x86_64-unknown-none" + ], + "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))": [ + "aarch64-unknown-linux-gnu", + "aarch64-unknown-nixos-gnu" + ], + "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))": [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-sim" + ], + "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))": [], + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-pc-windows-msvc", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-nixos-gnu", + "aarch64-unknown-nto-qnx710", + "i686-apple-darwin", + "i686-linux-android", + "i686-pc-windows-msvc", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu", + "x86_64-unknown-none" + ], + "cfg(curve25519_dalek_backend = \"fiat\")": [], + "cfg(target_arch = \"x86_64\")": [ + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu", + "x86_64-unknown-none" + ], + "cfg(target_os = \"wasi\")": [ + "wasm32-wasi" + ], + "cfg(unix)": [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-nixos-gnu", + "aarch64-unknown-nto-qnx710", + "arm-unknown-linux-gnueabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabi", + "i686-apple-darwin", + "i686-linux-android", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu" + ], + "i686-apple-darwin": [ + "i686-apple-darwin" + ], + "i686-linux-android": [ + "i686-linux-android" + ], + "i686-pc-windows-msvc": [ + "i686-pc-windows-msvc" + ], + "i686-unknown-freebsd": [ + "i686-unknown-freebsd" + ], + "i686-unknown-linux-gnu": [ + "i686-unknown-linux-gnu" + ], + "powerpc-unknown-linux-gnu": [ + "powerpc-unknown-linux-gnu" + ], + "riscv32imc-unknown-none-elf": [ + "riscv32imc-unknown-none-elf" + ], + "riscv64gc-unknown-none-elf": [ + "riscv64gc-unknown-none-elf" + ], + "s390x-unknown-linux-gnu": [ + "s390x-unknown-linux-gnu" + ], + "thumbv7em-none-eabi": [ + "thumbv7em-none-eabi" + ], + "thumbv8m.main-none-eabi": [ + "thumbv8m.main-none-eabi" + ], + "wasm32-unknown-unknown": [ + "wasm32-unknown-unknown" + ], + "wasm32-wasi": [ + "wasm32-wasi" + ], + "x86_64-apple-darwin": [ + "x86_64-apple-darwin" + ], + "x86_64-apple-ios": [ + "x86_64-apple-ios" + ], + "x86_64-fuchsia": [ + "x86_64-fuchsia" + ], + "x86_64-linux-android": [ + "x86_64-linux-android" + ], + "x86_64-pc-windows-msvc": [ + "x86_64-pc-windows-msvc" + ], + "x86_64-unknown-freebsd": [ + "x86_64-unknown-freebsd" + ], + "x86_64-unknown-linux-gnu": [ + "x86_64-unknown-linux-gnu" + ], + "x86_64-unknown-nixos-gnu": [ + "x86_64-unknown-nixos-gnu" + ], + "x86_64-unknown-none": [ + "x86_64-unknown-none" + ] + }, + "direct_deps": [ + "aead 0.5.2", + "aes 0.8.4", + "aes-gcm 0.10.3", + "aes-gcm-siv 0.11.1", + "cbc 0.1.2", + "cfg-if 1.0.0", + "ctr 0.9.2", + "ed25519-dalek 2.1.1", + "hkdf 0.12.4", + "hmac 0.12.1", + "lazy_static 1.4.0", + "nom 7.1.3", + "p256 0.13.2", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "sec1 0.7.3", + "sha2 0.10.8", + "strum 0.25.0", + "strum_macros 0.25.3", + "subtle 2.5.0", + "thiserror 1.0.58", + "tinyvec 1.6.0", + "x25519-dalek 2.0.1" + ], + "direct_dev_deps": [] +}
diff --git a/bazel_placeholder/Cargo.lock b/bazel_placeholder/Cargo.lock new file mode 100644 index 0000000..bed8428 --- /dev/null +++ b/bazel_placeholder/Cargo.lock
@@ -0,0 +1,664 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "sha2", + "subtle", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "elliptic-curve", + "primeorder", +] + +[[package]] +name = "place_holder" +version = "0.1.0" +dependencies = [ + "aead", + "aes", + "aes-gcm", + "aes-gcm-siv", + "cbc", + "cfg-if", + "ctr", + "ed25519-dalek", + "hkdf", + "hmac", + "lazy_static", + "nom", + "p256", + "rand", + "rand_chacha", + "rand_core", + "sec1", + "sha2", + "strum", + "strum_macros", + "subtle", + "thiserror", + "tinyvec", + "x25519-dalek", +] + +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
diff --git a/bazel_placeholder/Cargo.toml b/bazel_placeholder/Cargo.toml new file mode 100644 index 0000000..e7ee82a --- /dev/null +++ b/bazel_placeholder/Cargo.toml
@@ -0,0 +1,32 @@ +[package] +name = "place_holder" +version = "0.1.0" +edition = "2021" +publish = false +rust-version = "1.77.1" + +[dependencies] +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +strum = { version = "0.25.0", default-features = false } +strum_macros = { version = "0.25.3", default-features = false } +thiserror = "1.0.51" +nom = { version = "7.1.3", default-features = false } +tinyvec = { version = "1.6.0", features = ["rustc_1_55"] } +cfg-if = "1.0.0" +aead = { version = "0.5.1", features = ["alloc"] } +aes = "0.8.3" +aes-gcm-siv = { version = "0.11.1", features = ["aes"], default-features = false } +aes-gcm = { version = "0.10.3", features = ["aes"], default-features = false } +rand = { version = "0.8.5" } +rand_core = { version = "0.6.4", features = ["getrandom"] } +rand_chacha = { version = "0.3.1", default-features = false } +cbc = { version = "0.1.2", features = ["block-padding", "alloc"], default-features = false } +ctr = "0.9.2" +ed25519-dalek = { version = "2.1.0", features = ["rand_core"], default-features = false } +hkdf = "0.12.3" +hmac = "0.12.1" +p256 = { version = "0.13.2", features = ["ecdh"], default-features = false } +x25519-dalek = { version = "2.0.0", default-features = false } +subtle = { version = "2.5.0", default-features = false } +sec1 = "0.7.3" +sha2 = { version = "0.10.8", default-features = false } \ No newline at end of file
diff --git a/bazel_placeholder/src/lib.rs b/bazel_placeholder/src/lib.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/bazel_placeholder/src/lib.rs
diff --git a/cmd-runner/Cargo.lock b/cmd-runner/Cargo.lock deleted file mode 100644 index 4dadf2e..0000000 --- a/cmd-runner/Cargo.lock +++ /dev/null
@@ -1,30 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "cmd-runner" -version = "0.1.0" -dependencies = [ - "anyhow", - "owo-colors", - "shell-escape", -] - -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "shell-escape" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
diff --git a/cmd-runner/Cargo.toml b/cmd-runner/Cargo.toml deleted file mode 100644 index e79317e..0000000 --- a/cmd-runner/Cargo.toml +++ /dev/null
@@ -1,11 +0,0 @@ -[package] -name = "cmd-runner" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -anyhow = "1.0.64" -shell-escape = "0.1.5" -owo-colors = "3.5.0" -
diff --git a/common/Cargo.lock b/common/Cargo.lock new file mode 100644 index 0000000..6a98fd6 --- /dev/null +++ b/common/Cargo.lock
@@ -0,0 +1,1482 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "build_scripts" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "cmd_runner", + "file-header", + "globset", + "log", + "xshell", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.4", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cmd_runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "file-header", + "globset", + "log", + "owo-colors", + "shell-escape", + "xshell", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "derive_fuzz_example" +version = "0.1.0" +dependencies = [ + "arbitrary", + "derive_fuzztest", + "libfuzzer-sys", + "quickcheck", +] + +[[package]] +name = "derive_fuzztest" +version = "0.1.0" +dependencies = [ + "arbitrary", + "derive_fuzztest_macro", + "proptest", + "proptest-arbitrary-interop", + "quickcheck", +] + +[[package]] +name = "derive_fuzztest_macro" +version = "0.1.0" +dependencies = [ + "derive_fuzztest", + "pretty_assertions", + "prettyplease", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "file-header" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5568149106e77ae33bc3a2c3ef3839cbe63ffa4a8dd4a81612a6f9dfdbc2e9f" +dependencies = [ + "crossbeam", + "lazy_static", + "license", + "thiserror", + "walkdir", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "handle_map" +version = "0.1.0" +dependencies = [ + "criterion", + "lazy_static", + "lock_adapter", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "java-locator" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90003f2fd9c52f212c21d8520f1128da0080bad6fff16b68fe6e7f2f0c3780c2" +dependencies = [ + "glob", + "lazy_static", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "java-locator", + "jni-sys", + "libloading", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "license" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778718185117620a06e95d2b1e57d50166b1d6bfad93c8abfc1b3344c863ad8c" +dependencies = [ + "reword", + "serde", + "serde_json", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_adapter" +version = "0.1.0" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "pourover" +version = "0.1.0" +dependencies = [ + "jni", + "pourover_macro", +] + +[[package]] +name = "pourover_macro" +version = "0.1.0" +dependencies = [ + "jni", + "nom", + "pourover", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "prettyplease" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-arbitrary-interop" +version = "0.1.0" +source = "git+https://github.com/brson/proptest-arbitrary-interop.git?branch=incorrect-format#9ae407e9805feb109b3d49cc737166bda7e698c3" +dependencies = [ + "arbitrary", + "proptest", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger", + "log", + "rand", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reword" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe272098dce9ed76b479995953f748d1851261390b08f8a0ff619c885a1f0765" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000..9e8972b --- /dev/null +++ b/common/Cargo.toml
@@ -0,0 +1,84 @@ +[workspace] +members = [ + "build_scripts", + "cmd_runner", + "derive_fuzztest", + "derive_fuzztest/fuzz", + "derive_fuzztest_macro", + "handle_map", + "lock_adapter", + "pourover", + "pourover_macro", +] +default-members = ["build_scripts"] +resolver = "2" + +[workspace.lints.rust] +missing_docs = "deny" +trivial_casts = "deny" +trivial_numeric_casts = "deny" +unsafe_code = "deny" +unsafe_op_in_unsafe_fn = "deny" +unused_extern_crates = "deny" +unused_import_braces = "deny" +unused_results = "deny" + +[workspace.lints.clippy] +expect_used = "deny" +indexing_slicing = "deny" +panic = "deny" +unwrap_used = "deny" + +[workspace.dependencies] +# local crates +cmd_runner = { path = "cmd_runner" } +derive_fuzztest = { path = "derive_fuzztest" } +derive_fuzztest_macro = { path = "derive_fuzztest_macro" } +lock_adapter = { path = "lock_adapter" } +handle_map = { path = "handle_map" } +pourover = { path = "pourover" } +pourover_macro = { path = "pourover_macro" } + +# from crates.io +anyhow = "1.0.75" +arbitrary = "1.3.2" +clap = { version = "4.4.11", features = ["derive"] } +criterion = { version = "0.5.1", features = ["html_reports"] } +jni = "0.21.1" +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +libfuzzer-sys = "0.4.7" +nom = { version = "7.1.3", default-features = false } +pretty_assertions = "1.4.0" +prettyplease = "0.2.16" +proc-macro2 = "1.0" +proptest = "1.4.0" +proptest-arbitrary-interop = { git = "https://github.com/brson/proptest-arbitrary-interop.git", branch = "incorrect-format" } +quickcheck = "1.0.3" +quote = "1.0" +spin = { version = "0.9.8", features = ["once", "lock_api", "rwlock"] } +syn = { version = "2.0", features = ["full"] } +xshell = "0.2.6" + +[workspace.package] +version = "0.1.0" +edition = "2021" +publish = false + +[profile.test] +# speed up test execution +opt-level = 3 + +[profile.bench] +# Since xts, ldt, etc are in separate crates, use LTO to allow cross-crate inlining. +# fat vs thin: thin compiles a lot faster, and doesn't seem any slower. +lto = "thin" + +# build profile optimized for size +[profile.release-min-size] +inherits = "release" +panic = "abort" +codegen-units = 1 +lto = true +# z optimizes for size +opt-level = "z" +strip = true
diff --git a/common/build_scripts/Cargo.toml b/common/build_scripts/Cargo.toml new file mode 100644 index 0000000..8f9d217 --- /dev/null +++ b/common/build_scripts/Cargo.toml
@@ -0,0 +1,16 @@ +[package] +name = "build_scripts" +version.workspace = true +edition.workspace = true +publish.workspace = true +rust-version = "1.71.0" + +[dependencies] +anyhow.workspace = true +clap.workspace = true +xshell.workspace = true +cmd_runner.workspace = true +log = "0.4.21" +file-header = "0.1.2" +chrono = "0.4.37" +globset = "0.4.14"
diff --git a/common/build_scripts/src/license.rs b/common/build_scripts/src/license.rs new file mode 100644 index 0000000..113b7a0 --- /dev/null +++ b/common/build_scripts/src/license.rs
@@ -0,0 +1,65 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cmd_runner::license_checker::LicenseChecker; + +pub const LICENSE_CHECKER: LicenseChecker = LicenseChecker { + ignore: &[ + "**/android/build/**", + "**/target/**", + "**/.idea/**", + "**/cmake-build/**", + "**/java/build/**", + "**/java/*/build/**", + "**/*.toml", + "**/*.md", + "**/*.lock", + "**/*.json", + "**/*.rsp", + "**/*.patch", + "**/*.dockerignore", + "**/*.apk", + "**/gradle/*", + "**/.gradle/*", + "**/.git*", + "**/*test*vectors.txt", + "**/auth_token.txt", + "**/*.mdb", + "**/.DS_Store", + "**/fuzz/corpus/**", + "**/.*.swp", + "**/*.vim", + "**/*.properties", + "**/third_party/**", + "**/*.png", + "**/*.ico", + "**/node_modules/**", + "**/.angular/**", + "**/.editorconfig", + "**/*.class", + "**/fuzz/artifacts/**", + "**/cmake-build-debug/**", + "**/tags", + ], +}; + +#[cfg(test)] +mod tests { + use super::LICENSE_CHECKER; + + #[test] + fn new_ignore_is_likely_buggy() { + LICENSE_CHECKER.check_new_ignore_is_likely_buggy(); + } +}
diff --git a/common/build_scripts/src/main.rs b/common/build_scripts/src/main.rs new file mode 100644 index 0000000..53fd178 --- /dev/null +++ b/common/build_scripts/src/main.rs
@@ -0,0 +1,66 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::path; + +use clap::Parser; +use cmd_runner::{ + cargo_workspace::{CargoOptions, CargoWorkspaceSubcommand, FormatterOptions}, + license_checker::LicenseSubcommand, +}; +use license::LICENSE_CHECKER; +use xshell::Shell; + +mod license; + +#[derive(clap::Parser)] +struct Cli { + #[clap(subcommand)] + subcommand: Subcommand, +} + +#[derive(clap::Subcommand, Debug, Clone)] +enum Subcommand { + VerifyCi { + #[command(flatten)] + cargo_options: CargoOptions, + }, + #[command(flatten)] + CargoWorkspace(CargoWorkspaceSubcommand), + #[command(flatten)] + License(LicenseSubcommand), +} + +fn main() -> anyhow::Result<()> { + let args = Cli::parse(); + let root_dir = path::Path::new( + &std::env::var_os("CARGO_MANIFEST_DIR") + .expect("Must be run via Cargo to establish root directory"), + ) + .parent() + .expect("Workspace directory should exist") + .to_path_buf(); + let sh = Shell::new()?; + sh.change_dir(&root_dir); + match args.subcommand { + Subcommand::VerifyCi { cargo_options } => { + cargo_options.check_workspace(&sh, "common")?; + FormatterOptions { reformat: false }.check_format(&sh)?; + LICENSE_CHECKER.check(&root_dir)?; + } + Subcommand::CargoWorkspace(workspace) => workspace.run("common", &sh)?, + Subcommand::License(license) => license.run(&LICENSE_CHECKER, &root_dir)?, + } + Ok(()) +}
diff --git a/common/cmd_runner/Cargo.lock b/common/cmd_runner/Cargo.lock new file mode 100644 index 0000000..3f3f5e1 --- /dev/null +++ b/common/cmd_runner/Cargo.lock
@@ -0,0 +1,714 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "cmd-runner" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "file-header", + "globset", + "log", + "owo-colors", + "shell-escape", + "xshell", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "file-header" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5568149106e77ae33bc3a2c3ef3839cbe63ffa4a8dd4a81612a6f9dfdbc2e9f" +dependencies = [ + "crossbeam", + "lazy_static", + "license", + "thiserror", + "walkdir", +] + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "license" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778718185117620a06e95d2b1e57d50166b1d6bfad93c8abfc1b3344c863ad8c" +dependencies = [ + "reword", + "serde", + "serde_json", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reword" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe272098dce9ed76b479995953f748d1851261390b08f8a0ff619c885a1f0765" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
diff --git a/common/cmd_runner/Cargo.toml b/common/cmd_runner/Cargo.toml new file mode 100644 index 0000000..435b29f --- /dev/null +++ b/common/cmd_runner/Cargo.toml
@@ -0,0 +1,17 @@ +[package] +name = "cmd_runner" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[dependencies] +anyhow = "1.0.64" +shell-escape = "0.1.5" +owo-colors = "3.5.0" +xshell = "0.2.6" +clap = { version = "4.5.4", features = ["derive"] } +file-header = "0.1.2" +chrono = "0.4.37" +log = "0.4.21" +globset = "0.4.14" +
diff --git a/common/cmd_runner/src/cargo_workspace.rs b/common/cmd_runner/src/cargo_workspace.rs new file mode 100644 index 0000000..2b6840e --- /dev/null +++ b/common/cmd_runner/src/cargo_workspace.rs
@@ -0,0 +1,106 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::ffi::OsStr; + +use xshell::cmd; + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum CargoWorkspaceSubcommand { + /// Checks test, clippy, and cargo deny in the workspace + CheckWorkspace(CargoOptions), + /// Checks the formatting of the workspace + CheckFormat(FormatterOptions), +} + +impl CargoWorkspaceSubcommand { + pub fn run(&self, tag: &str, sh: &xshell::Shell) -> anyhow::Result<()> { + match self { + CargoWorkspaceSubcommand::CheckWorkspace(cargo_options) => { + cargo_options.check_workspace(sh, tag) + } + CargoWorkspaceSubcommand::CheckFormat(formatter_options) => { + formatter_options.check_format(sh) + } + } + } +} + +#[derive(clap::Args, Debug, Clone, Default)] +pub struct CargoOptions { + #[arg(long, help = "whether to run cargo with --locked")] + locked: bool, + #[arg(long, help = "gather coverage metrics")] + coverage: bool, +} + +impl CargoOptions { + /// Run `cargo test` or `cargo llvm-cov` depending on the configured options. + pub fn test<'sh, S: AsRef<OsStr>>( + &self, + sh: &'sh xshell::Shell, + tag: &str, + args: impl IntoIterator<Item = S>, + ) -> xshell::Cmd<'sh> { + let locked = if self.locked { "--locked" } else { "" }; + if self.coverage { + cmd!( + sh, + "cargo llvm-cov {locked} {args...} --lcov --output-path target/{tag}.info -- --color=always" + ) + } else { + cmd!(sh, "cargo test {locked} {args...} -- --color=always") + } + } + + /// Run the default set of checks on a cargo workspace + pub fn check_workspace(&self, sh: &xshell::Shell, tag: &str) -> anyhow::Result<()> { + self.test(sh, tag, ["--workspace"]).run()?; + cmd!( + sh, + "cargo clippy --all-targets --workspace -- --deny warnings" + ) + .run()?; + cmd!(sh, "cargo deny --workspace check").run()?; + // ensure the docs are valid (cross-references to other code, etc) + cmd!( + sh, + "cargo doc --quiet --workspace --no-deps --document-private-items + --target-dir target/dist_docs/{tag}" + ) + .env("RUSTDOCFLAGS", "--deny warnings") + .run()?; + Ok(()) + } +} + +#[derive(clap::Args, Debug, Clone, Default)] +pub struct FormatterOptions { + #[arg( + long, + help = "reformat files files in the workspace with the code formatter" + )] + pub reformat: bool, +} + +impl FormatterOptions { + pub fn check_format(&self, sh: &xshell::Shell) -> anyhow::Result<()> { + if self.reformat { + cmd!(sh, "cargo fmt").run()?; + } else { + cmd!(sh, "cargo fmt --check").run()?; + } + Ok(()) + } +}
diff --git a/cmd-runner/src/lib.rs b/common/cmd_runner/src/lib.rs similarity index 98% rename from cmd-runner/src/lib.rs rename to common/cmd_runner/src/lib.rs index fa2f1f4..8c45df8 100644 --- a/cmd-runner/src/lib.rs +++ b/common/cmd_runner/src/lib.rs
@@ -16,6 +16,9 @@ use owo_colors::OwoColorize as _; use std::{collections, env, ffi, io, io::BufRead, path, process, thread}; +pub mod cargo_workspace; +pub mod license_checker; + pub fn run_cmd_shell( dir: &path::Path, cmd: impl AsRef<ffi::OsStr>,
diff --git a/common/cmd_runner/src/license_checker.rs b/common/cmd_runner/src/license_checker.rs new file mode 100644 index 0000000..19286bb --- /dev/null +++ b/common/cmd_runner/src/license_checker.rs
@@ -0,0 +1,105 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use chrono::Datelike; +use file_header::{check_headers_recursively, license::spdx::*}; +use std::path; + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum LicenseSubcommand { + /// Checks the workspace 3rd party crates and makes sure they have a valid license + CheckLicenseHeaders, + /// Generate new headers for any files that are missing them + AddLicenseHeaders, +} + +impl LicenseSubcommand { + pub fn run(&self, checker: &LicenseChecker, root: &path::Path) -> anyhow::Result<()> { + match self { + LicenseSubcommand::CheckLicenseHeaders => checker.check(root)?, + LicenseSubcommand::AddLicenseHeaders => checker.add_missing(root)?, + } + Ok(()) + } +} + +pub struct LicenseChecker { + pub ignore: &'static [&'static str], +} + +impl LicenseChecker { + pub fn check(&self, root: &path::Path) -> anyhow::Result<()> { + log::info!("Checking license headers"); + let ignore = self.ignore_globset()?; + let results = check_headers_recursively( + root, + |p| !ignore.is_match(p), + APACHE_2_0.build_header(YearCopyrightOwnerValue::new( + u32::try_from(chrono::Utc::now().year())?, + "Google LLC".to_string(), + )), + 4, + )?; + + for path in results.no_header_files.iter() { + eprintln!("Header not present: {path:?}"); + } + + for path in results.binary_files.iter() { + eprintln!("Binary file: {path:?}"); + } + if !results.binary_files.is_empty() { + eprintln!("Consider adding binary files to the ignore list in src/licence.rs."); + } + + if results.has_failure() { + Err(anyhow::anyhow!("License header check failed")) + } else { + Ok(()) + } + } + + pub fn add_missing(&self, root: &path::Path) -> anyhow::Result<()> { + let ignore = self.ignore_globset()?; + for p in file_header::add_headers_recursively( + root, + |p| !ignore.is_match(p), + APACHE_2_0.build_header(YearCopyrightOwnerValue::new( + u32::try_from(chrono::Utc::now().year())?, + "Google LLC".to_string(), + )), + )? { + println!("Added header: {:?}", p); + } + + Ok(()) + } + + fn ignore_globset(&self) -> Result<globset::GlobSet, globset::Error> { + let mut builder = globset::GlobSet::builder(); + for lic in self.ignore { + builder.add(globset::Glob::new(lic)?); + } + builder.build() + } + + pub fn check_new_ignore_is_likely_buggy(&self) { + for dir in self.ignore { + assert!( + dir.starts_with("**/"), + "Matching on the root filesystem is likely unintended" + ); + } + } +}
diff --git a/common/deny.toml b/common/deny.toml new file mode 100644 index 0000000..bd3f18b --- /dev/null +++ b/common/deny.toml
@@ -0,0 +1,186 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +graph.targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #{ triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +version = 2 +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url(s) of the advisory databases to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + # comment explaining why we have to ignore it + # "RUSTSEC-FOO", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# If this is true, then cargo deny will use the git executable to fetch advisory database. +# If this is false, then it uses a built-in git library. +# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. +# See Git Authentication for more information about setting up git authentication. +#git-fetch-with-cli = true + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +version = 2 +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +allow = [ + "MIT", + "Apache-2.0", + "Unicode-DFS-2016", + "ISC", +] +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # Each entry is the crate and version constraint, and its specific allow + # list + +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +#[[licenses.clarify]] +# The name of the crate the clarification applies to +#name = "ring" +# The optional version constraint for the crate +#version = "*" +# The SPDX expression for the license requirements of the crate +#expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +#license-files = [ + # Each entry is a crate relative path, and the (opaque) hash of its contents + #{ path = "LICENSE", hash = 0xbd0eed23 } +#] + +[[licenses.clarify]] +name = "ring" +version = "*" +expression = "MIT AND ISC AND OpenSSL" +license-files = [ + # Each entry is a crate relative path, and the (opaque) hash of its contents + { path = "LICENSE", hash = 0xbd0eed23 } +] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries. +# To see how to mark a crate as unpublished (to the official registry), +# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. +ignore = true +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "allow" +# Lint level for when a crate version requirement is `*` +wildcards = "allow" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + #{ name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, +] +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite +skip-tree = [ + #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "warn" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "warn" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] \ No newline at end of file
diff --git a/common/derive_fuzztest/Cargo.toml b/common/derive_fuzztest/Cargo.toml new file mode 100644 index 0000000..6a22ce5 --- /dev/null +++ b/common/derive_fuzztest/Cargo.toml
@@ -0,0 +1,24 @@ +[package] +name = "derive_fuzztest" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[dependencies] +arbitrary.workspace = true +derive_fuzztest_macro.workspace = true +proptest = { workspace = true, optional = true } +proptest-arbitrary-interop = { workspace = true, optional = true } +quickcheck = { workspace = true, optional = true } + +[features] +default = ["quickcheck"] +quickcheck = ["dep:quickcheck", "derive_fuzztest_macro/quickcheck"] +proptest = [ + "dep:proptest", + "dep:proptest-arbitrary-interop", + "derive_fuzztest_macro/proptest", +] + +[lints] +workspace = true
diff --git a/common/derive_fuzztest/fuzz/.gitignore b/common/derive_fuzztest/fuzz/.gitignore new file mode 100644 index 0000000..b94a8f4 --- /dev/null +++ b/common/derive_fuzztest/fuzz/.gitignore
@@ -0,0 +1 @@ +/corpus \ No newline at end of file
diff --git a/common/derive_fuzztest/fuzz/Cargo.toml b/common/derive_fuzztest/fuzz/Cargo.toml new file mode 100644 index 0000000..1f493b6 --- /dev/null +++ b/common/derive_fuzztest/fuzz/Cargo.toml
@@ -0,0 +1,16 @@ +[package] +name = "derive_fuzz_example" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[package.metadata] +cargo-fuzz = true + +[dependencies] +arbitrary.workspace = true +derive_fuzztest.workspace = true +quickcheck.workspace = true + +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true
diff --git a/common/derive_fuzztest/fuzz/src/bin/arbitrary.rs b/common/derive_fuzztest/fuzz/src/bin/arbitrary.rs new file mode 100644 index 0000000..8f8d77b --- /dev/null +++ b/common/derive_fuzztest/fuzz/src/bin/arbitrary.rs
@@ -0,0 +1,32 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(fuzzing, no_main)] + +use arbitrary::{Arbitrary, Unstructured}; +use derive_fuzztest::fuzztest; + +#[derive(Debug, Clone)] +pub struct SmallU8(u8); + +impl<'a> Arbitrary<'a> for SmallU8 { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { + Ok(SmallU8(u.int_in_range(0..=127)?)) + } +} + +#[fuzztest] +pub fn test(a: SmallU8, b: SmallU8) { + let _ = a.0 + b.0; // Succeeds because our custom arbitrary impl only generates 0-127 so it never overflows +}
diff --git a/nearby/util/pourover_macro_core/src/lib.rs b/common/derive_fuzztest/fuzz/src/bin/integer_add.rs similarity index 74% copy from nearby/util/pourover_macro_core/src/lib.rs copy to common/derive_fuzztest/fuzz/src/bin/integer_add.rs index ae06345..38b8172 100644 --- a/nearby/util/pourover_macro_core/src/lib.rs +++ b/common/derive_fuzztest/fuzz/src/bin/integer_add.rs
@@ -12,5 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod jni_method; -pub use jni_method::jni_method; +#![cfg_attr(fuzzing, no_main)] + +use derive_fuzztest::fuzztest; + +#[fuzztest] +pub fn test(a: u8, b: u8) { + let _ = a.checked_add(b); + // a + b; // This fails because a + b can overflow. +}
diff --git a/common/derive_fuzztest/src/lib.rs b/common/derive_fuzztest/src/lib.rs new file mode 100644 index 0000000..c0dd11c --- /dev/null +++ b/common/derive_fuzztest/src/lib.rs
@@ -0,0 +1,141 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Derive macros that generates both a fuzz target for use with `cargo fuzz`, and a property test +//! (via `quickcheck` or `proptest`) for use with `cargo test`. +//! +//! The reason for having both is that property testing allows for quick iteration to make sure the +//! test works, and can be checked in presubmit CI, while fuzzing can test the input space more +//! exhaustively and run continuously. +//! +//! # Example +//! +//! ```no_run +//! #![cfg_attr(fuzzing, no_main)] +//! +//! #[derive_fuzztest::fuzztest] +//! fn transitive_ord(a: u32, b: u32, c: u32) { +//! if a >= b && b >= c { +//! assert!(a >= c); +//! } +//! if a <= b && b <= c { +//! assert!(a <= c); +//! } +//! } +//! +//! #[test] +//! fn additional_test_here() { +//! /* ... */ +//! } +//! ``` +//! +//! # Usage +//! +//! +//! Run the generated property tests +//! ```sh +//! cargo test +//! ``` +//! +//! Run continuous fuzzing +//! ```sh +//! cargo +nightly fuzz run <binary name> +//! ``` +//! +//! # Crate structure +//! +//! If you use `#[fuzz]` or `#[fuzztest]`, the fuzz target imposes the following requirements: +//! +//! * The target must be in a separate `[[bin]]` target that only contains a single fuzz target. +//! * The crate containing the bin target has `[package.metadata] cargo-fuzz = true` +//! * The bin target is annotated with `#![cfg_attr(fuzzing, no_main)]` +//! +//! The recommended structure for your crate `foo` is to put your tests under `foo/fuzz/src/bin`: +//! +//! ```text +//! foo +//! ├── fuzz +//! │ ├── src +//! │ │ └── bin +//! │ │ └── fuzz_target_1.rs +//! │ └── Cargo.toml +//! ├── src +//! │ └── [project source] +//! └── Cargo.toml +//! ``` +//! +//! This is different from the default structure generated by `cargo fuzz init` or `cargo fuzz add` +//! so that we can take advantage of [target +//! auto-discovery](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#target-auto-discovery). +//! If you prefer, the default structure generated by `cargo fuzz` can also work, but make sure you +//! remove `test = false` from the generated target in `Cargo.toml`. +//! +//! You will also need to declare a dependency on the `libfuzzer-sys` crate, but only if fuzzing is +//! requested: +//! +//! ```toml +//! [target.'cfg(fuzzing)'.dependencies] +//! libfuzzer-sys = "*" +//! ``` +//! +//! (The reason for this conditional dependency is that `libfuzzer-sys` injects a main function to +//! the resulting binary, and there will be linking failures if we link that in without defining a +//! corresponding `fuzz_target`.) +//! +//! # Features +//! +//! * `quickcheck` (default) — Enable generation of +//! [`quickcheck`](https://docs.rs/quickcheck/latest/quickcheck/) property tests. +//! * `proptest` — Enable generation of [`proptest`](https://docs.rs/proptest/latest/proptest/) +//! property tests. +//! +//! #### See also +//! * [Announcing Better Support for Fuzzing with Structured Inputs in +//! Rust](https://fitzgeraldnick.com/2020/01/16/better-support-for-fuzzing-structured-inputs-in-rust.html#how-is-all-this-different-from-quickcheck-and-proptest) +//! * [Bridging Fuzzing and Property +//! Testing](https://blog.yoshuawuyts.com/bridging-fuzzing-and-property-testing/) + +pub use derive_fuzztest_macro::{fuzz, fuzztest, proptest}; + +#[doc(hidden)] +pub mod reexport { + #[cfg(feature = "proptest")] + pub use proptest; + #[cfg(feature = "proptest")] + pub use proptest_arbitrary_interop; + #[cfg(feature = "quickcheck")] + pub use quickcheck; +} + +#[cfg(feature = "quickcheck")] +#[doc(hidden)] +pub mod arbitrary_bridge { + + /// Wrapper type that allows `arbitrary::Arbitrary` to be used as `quickcheck::Arbitrary` + #[derive(Debug, Clone)] + pub struct ArbitraryAdapter<T: for<'a> arbitrary::Arbitrary<'a>>( + pub Result<T, arbitrary::Error>, + ); + + impl<T> quickcheck::Arbitrary for ArbitraryAdapter<T> + where + T: for<'a> arbitrary::Arbitrary<'a> + Clone + 'static, + { + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + let bytes = Vec::<u8>::arbitrary(g); + let mut unstructured = arbitrary::Unstructured::new(&bytes); + Self(T::arbitrary(&mut unstructured)) + } + } +}
diff --git a/common/derive_fuzztest_macro/Cargo.toml b/common/derive_fuzztest_macro/Cargo.toml new file mode 100644 index 0000000..37b480a --- /dev/null +++ b/common/derive_fuzztest_macro/Cargo.toml
@@ -0,0 +1,23 @@ +[package] +name = "derive_fuzztest_macro" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[dependencies] +quote.workspace = true +proc-macro2.workspace = true +syn = { workspace = true, features = ["extra-traits"]} + +[dev-dependencies] +derive_fuzztest.workspace = true +pretty_assertions.workspace = true +prettyplease.workspace = true + +[features] +quickcheck = [] +proptest = [] + +[lib] +proc-macro = true +doc = false
diff --git a/common/derive_fuzztest_macro/src/lib.rs b/common/derive_fuzztest_macro/src/lib.rs new file mode 100644 index 0000000..beb692a --- /dev/null +++ b/common/derive_fuzztest_macro/src/lib.rs
@@ -0,0 +1,463 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Internal crate for use by [`derive_fuzztest`](../derive_fuzztest/index.html). See the +//! documentation there for usage information. + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use syn::{parse::Nothing, spanned::Spanned, ItemFn, Pat, PatType, Type}; + +/// Define a fuzz test. +/// +/// All input parameters of the given function must implement `arbitrary::Arbitrary`. +/// +/// This macro derives new items based on the given function. +/// 1. A `fuzz_target!` is generated that can be used with `cargo fuzz`. +/// 2. Property tests (`quickcheck` or `proptest`, based on which features are enabled) are +/// generated that can be tested using `cargo test`. +/// +/// See the crate documentation [`derive_fuzztest`](../derive_fuzztest/index.html) for details. +#[proc_macro_attribute] +pub fn fuzztest(attr: TokenStream, item: TokenStream) -> TokenStream { + fuzztest_impl(attr.into(), item.into()) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn fuzztest_impl(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> { + syn::parse2::<Nothing>(attr)?; + let func = syn::parse2::<ItemFn>(item)?; + let fn_def = FunctionDefinition::parse(func)?; + let original_fn = &fn_def.func; + let fuzz_target = derive_fuzz_target(&fn_def); + let proptest_target = proptest::derive_proptest(&fn_def); + let quickcheck_target = quickcheck::derive_quickcheck(&fn_def); + + Ok(quote! { + #[allow(unused)] + #original_fn + #fuzz_target + #proptest_target + #quickcheck_target + }) +} + +/// Define a fuzz target only without corresponding test. +/// +/// All input parameters of the given function must implement `arbitrary::Arbitrary`. +/// +/// This macro derives a `fuzz_target!` that can be used with `cargo fuzz`. If you wish to generate +/// property tests that can be used with `cargo test` as well, use [`fuzztest`][macro@fuzztest]. +/// +/// See the crate documentation [`derive_fuzztest`](../derive_fuzztest/index.html) for details. +#[proc_macro_attribute] +pub fn fuzz(attr: TokenStream, item: TokenStream) -> TokenStream { + fuzz_impl(attr.into(), item.into()) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn fuzz_impl(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> { + syn::parse2::<Nothing>(attr)?; + let func = syn::parse2::<ItemFn>(item)?; + let fn_def = FunctionDefinition::parse(func)?; + let original_fn = &fn_def.func; + let fuzz_target = derive_fuzz_target(&fn_def); + + Ok(quote! { + #[allow(unused)] + #original_fn + #fuzz_target + }) +} + +/// Define a property test. +/// +/// This is similar to using `quickcheck!` or `proptest::proptest!` directly. +/// +/// All input parameters of the given function must implement `arbitrary::Arbitrary`. +/// +/// Unlike [`fuzztest`][macro@fuzztest], this macro does not have to be placed in a `[[bin]]` target +/// and a single file can contain multiple of these tests. The generated tests can be run with +/// `cargo test` as usual. +#[proc_macro_attribute] +pub fn proptest(attr: TokenStream, item: TokenStream) -> TokenStream { + proptest_impl(attr.into(), item.into()) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn proptest_impl(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> { + syn::parse2::<Nothing>(attr)?; + let func = syn::parse2::<ItemFn>(item)?; + let fn_def = FunctionDefinition::parse(func)?; + let original_fn = &fn_def.func; + let proptest_target = proptest::derive_proptest(&fn_def); + + Ok(quote! { + #[allow(unused)] + #original_fn + #proptest_target + }) +} + +fn derive_fuzz_target(fn_def: &FunctionDefinition) -> proc_macro2::TokenStream { + let FunctionDefinition { func, args, types } = fn_def; + let func_ident = &func.sig.ident; + quote! { + #[automatically_derived] + #[cfg(fuzzing)] + ::libfuzzer_sys::fuzz_target!(|args: ( #(#types),* )| { + let ( #(#args),* ) = args; // https://github.com/rust-fuzz/libfuzzer/issues/77 + #func_ident ( #(#args),* ) + }); + + #[cfg(not(any(fuzzing, rust_analyzer)))] + fn main() { + ::std::unreachable!("Run this target with `cargo fuzz` or `cargo test` instead"); + } + } +} + +#[cfg(any(feature = "quickcheck", test))] +mod quickcheck { + use crate::FunctionDefinition; + use quote::quote; + + pub(crate) fn derive_quickcheck(fn_def: &FunctionDefinition) -> proc_macro2::TokenStream { + let FunctionDefinition { func, args, types } = fn_def; + let func_ident = &func.sig.ident; + let adapted_types: Vec<_> = types + .iter() + .map(|ty| quote! { ArbitraryAdapter<#ty> }) + .collect(); + let arg_pattern: Vec<_> = args + .iter() + .map(|arg| quote! { ArbitraryAdapter(::core::result::Result::Ok(#arg)) }) + .collect(); + let test_name = quote::format_ident!("quickcheck_{func_ident}"); + quote! { + #[automatically_derived] + #[test] + fn #test_name() { + use ::derive_fuzztest::reexport::quickcheck::TestResult; + use ::derive_fuzztest::arbitrary_bridge::ArbitraryAdapter; + + fn inner(args: (#(#adapted_types),*)) -> TestResult { + let (#(#arg_pattern),*) = args else { return TestResult::discard() }; + match ::std::panic::catch_unwind(move || { + #func_ident ( #(#args),* ); + }) { + ::core::result::Result::Ok(()) => TestResult::passed(), + ::core::result::Result::Err(e) => TestResult::error(::std::format!("{e:?}")), + } + } + + ::derive_fuzztest::reexport::quickcheck::QuickCheck::new().tests(1024) + .quickcheck(inner as fn(_) -> TestResult); + } + } + } +} + +#[cfg(not(any(feature = "quickcheck", test)))] +mod quickcheck { + use crate::FunctionDefinition; + + pub(crate) fn derive_quickcheck(_fn_def: &FunctionDefinition) -> proc_macro2::TokenStream { + proc_macro2::TokenStream::default() + } +} + +#[cfg(any(feature = "proptest", test))] +mod proptest { + use crate::FunctionDefinition; + use quote::quote; + use syn::{Ident, Signature}; + + pub(crate) fn derive_proptest(fn_def: &FunctionDefinition) -> proc_macro2::TokenStream { + let FunctionDefinition { func, args, types } = fn_def; + let func_attrs = &func.attrs; + let Signature { + constness, + asyncness, + unsafety, + abi, + fn_token, + ident, + generics, + paren_token: _, + inputs: _, + variadic: _, + output, + } = &func.sig; + let proptest_ident = Ident::new(&format!("proptest_{ident}"), ident.span()); + quote! { + #[automatically_derived] + #[cfg(test)] + mod #proptest_ident { + use super::*; + use ::derive_fuzztest::reexport::proptest; + use ::derive_fuzztest::reexport::proptest_arbitrary_interop::arb; + + proptest::proptest! { + #![proptest_config(proptest::prelude::ProptestConfig { + cases: 1024, + failure_persistence: Some(Box::new(proptest::test_runner::FileFailurePersistence::WithSource("regression"))), + ..Default::default() + })] + #[test] + #(#func_attrs)* + #constness #asyncness #unsafety #abi #fn_token #proptest_ident #generics ( args in arb::<(#(#types),*)>() ) #output { + let (#(#args),*) = args; + #ident ( #(#args),* ); + } + } + } + } + } +} + +#[cfg(not(any(feature = "proptest", test)))] +mod proptest { + use crate::FunctionDefinition; + + pub(crate) fn derive_proptest(_fn_def: &FunctionDefinition) -> proc_macro2::TokenStream { + proc_macro2::TokenStream::default() + } +} + +/// Representation of a function definition annotated with one of the attribute macros in this +/// crate. +struct FunctionDefinition { + func: ItemFn, + args: Vec<Pat>, + types: Vec<Type>, +} + +impl FunctionDefinition { + pub fn parse(func: ItemFn) -> syn::Result<Self> { + let (args, types) = func + .sig + .inputs + .clone() + .into_iter() + .map(|arg| match arg { + syn::FnArg::Receiver(arg_receiver) => Err(syn::Error::new( + arg_receiver.span(), + "Receiver not supported", + )), + syn::FnArg::Typed(PatType { + attrs: _, + pat, + colon_token: _, + ty, + }) => Ok((*pat, *ty)), + }) + .try_fold((Vec::new(), Vec::new()), |(mut args, mut types), result| { + result.map(|(arg, type_)| { + args.push(arg); + types.push(type_); + (args, types) + }) + })?; + Ok(Self { func, args, types }) + } +} + +#[cfg(test)] +mod tests { + use crate::{fuzz_impl, fuzztest_impl, proptest_impl}; + use quote::quote; + use syn::parse_quote; + + /// Assert that a token stream for a `syn::File` is the same as expected. + /// + /// Usage is similar to `assert_eq!`: + /// ```no_run + /// assert_syn_file!( + /// macro_impl(quote! { + /// fn foobar() {} + /// }), + /// quote! { + /// fn macro_rewritten_foobar() {} + /// } + /// ); + /// ``` + macro_rules! assert_syn_file { + ($actual:expr, $expected:expr) => { + let actual = syn::parse2::<syn::File>($actual).unwrap(); + let expected: syn::File = $expected; + assert!( + actual == expected, + "{}", + pretty_assertions::StrComparison::new( + &prettyplease::unparse(&expected), + &prettyplease::unparse(&actual), + ) + ) + }; + } + + #[test] + fn test_fuzztest_expansion() { + assert_syn_file!( + fuzztest_impl( + quote! {}, + quote! { + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + } + ) + .unwrap(), + parse_quote! { + #[allow(unused)] + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + + #[automatically_derived] + #[cfg(fuzzing)] + ::libfuzzer_sys::fuzz_target!(|args: (&[u8])| { + let (input) = args; + foobar(input) + }); + + #[cfg(not(any(fuzzing, rust_analyzer)))] + fn main() { + ::std::unreachable!("Run this target with `cargo fuzz` or `cargo test` instead"); + } + + #[automatically_derived] + #[cfg(test)] + mod proptest_foobar { + use super::*; + use ::derive_fuzztest::reexport::proptest; + use ::derive_fuzztest::reexport::proptest_arbitrary_interop::arb; + proptest::proptest! { + #![proptest_config(proptest::prelude::ProptestConfig { + cases: 1024, + failure_persistence: Some(Box::new(proptest::test_runner::FileFailurePersistence::WithSource("regression"))), + ..Default::default() + })] + #[test] + fn proptest_foobar(args in arb::<(&[u8])>()) { + let (input) = args; + foobar(input); + } + } + } + + #[automatically_derived] + #[test] + fn quickcheck_foobar() { + use ::derive_fuzztest::reexport::quickcheck::TestResult; + use ::derive_fuzztest::arbitrary_bridge::ArbitraryAdapter; + + fn inner(args: (ArbitraryAdapter<&[u8]>)) -> TestResult { + let (ArbitraryAdapter(::core::result::Result::Ok(input))) = args else { + return TestResult::discard() + }; + match ::std::panic::catch_unwind(move || { + foobar(input); + }) { + ::core::result::Result::Ok(()) => TestResult::passed(), + ::core::result::Result::Err(e) => TestResult::error(::std::format!("{e:?}")), + } + } + ::derive_fuzztest::reexport::quickcheck::QuickCheck::new() + .tests(1024) + .quickcheck(inner as fn(_) -> TestResult); + } + } + ); + } + + #[test] + fn test_fuzz_expansion() { + assert_syn_file!( + fuzz_impl( + quote! {}, + quote! { + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + } + ) + .unwrap(), + parse_quote! { + #[allow(unused)] + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + + #[automatically_derived] + #[cfg(fuzzing)] + ::libfuzzer_sys::fuzz_target!(|args: (&[u8])| { + let (input) = args; + foobar(input) + }); + + #[cfg(not(any(fuzzing, rust_analyzer)))] + fn main() { + ::std::unreachable!("Run this target with `cargo fuzz` or `cargo test` instead"); + } + } + ); + } + + #[test] + fn test_proptest_expansion() { + assert_syn_file!( + proptest_impl( + quote! {}, + quote! { + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + } + ) + .unwrap(), + parse_quote! { + #[allow(unused)] + fn foobar(input: &[u8]) { + panic!("I am just a test") + } + + #[automatically_derived] + #[cfg(test)] + mod proptest_foobar { + use super::*; + use ::derive_fuzztest::reexport::proptest; + use ::derive_fuzztest::reexport::proptest_arbitrary_interop::arb; + proptest::proptest! { + #![proptest_config(proptest::prelude::ProptestConfig { + cases: 1024, + failure_persistence: Some(Box::new(proptest::test_runner::FileFailurePersistence::WithSource("regression"))), + ..Default::default() + })] + #[test] + fn proptest_foobar(args in arb::<(&[u8])>()) { + let (input) = args; + foobar(input); + } + } + } + } + ); + } +}
diff --git a/nearby/util/handle_map/Cargo.toml b/common/handle_map/Cargo.toml similarity index 100% rename from nearby/util/handle_map/Cargo.toml rename to common/handle_map/Cargo.toml
diff --git a/nearby/util/handle_map/benches/benches.rs b/common/handle_map/benches/benches.rs similarity index 91% rename from nearby/util/handle_map/benches/benches.rs rename to common/handle_map/benches/benches.rs index f1988ba..176a54e 100644 --- a/nearby/util/handle_map/benches/benches.rs +++ b/common/handle_map/benches/benches.rs
@@ -36,7 +36,10 @@ type BenchHandleMap = HandleMap<u8>; fn build_handle_map(num_shards: u8) -> BenchHandleMap { - let dimensions = HandleMapDimensions { num_shards, max_active_handles: MAX_ACTIVE_HANDLES }; + let dimensions = HandleMapDimensions { + num_shards, + max_active_handles: MAX_ACTIVE_HANDLES, + }; HandleMap::with_dimensions(dimensions) } @@ -97,12 +100,15 @@ let handle_map = build_handle_map(8); let handle_map_ref = &handle_map; // Perform repeated allocation/deallocation pairs - c.bench_function("single-threaded allocate/deallocate pairs (empty init state)", |b| { - b.iter(|| { - let handle = handle_map_ref.allocate(|| black_box(0xDD)).unwrap(); - handle_map_ref.deallocate(handle); - }) - }); + c.bench_function( + "single-threaded allocate/deallocate pairs (empty init state)", + |b| { + b.iter(|| { + let handle = handle_map_ref.allocate(|| black_box(0xDD)).unwrap(); + handle_map_ref.deallocate(handle); + }) + }, + ); } /// Benchmark for repeated allocation->deallocation starting @@ -192,18 +198,38 @@ num_writes: usize, } -const READS_ONLY: ReadWriteCount = ReadWriteCount { num_reads: 4, num_writes: 0 }; +const READS_ONLY: ReadWriteCount = ReadWriteCount { + num_reads: 4, + num_writes: 0, +}; -const READ_LEANING: ReadWriteCount = ReadWriteCount { num_reads: 3, num_writes: 1 }; +const READ_LEANING: ReadWriteCount = ReadWriteCount { + num_reads: 3, + num_writes: 1, +}; -const BALANCED: ReadWriteCount = ReadWriteCount { num_reads: 2, num_writes: 2 }; +const BALANCED: ReadWriteCount = ReadWriteCount { + num_reads: 2, + num_writes: 2, +}; -const WRITE_LEANING: ReadWriteCount = ReadWriteCount { num_reads: 1, num_writes: 3 }; +const WRITE_LEANING: ReadWriteCount = ReadWriteCount { + num_reads: 1, + num_writes: 3, +}; -const WRITES_ONLY: ReadWriteCount = ReadWriteCount { num_reads: 0, num_writes: 4 }; +const WRITES_ONLY: ReadWriteCount = ReadWriteCount { + num_reads: 0, + num_writes: 4, +}; -const READ_WRITE_COUNTS: [ReadWriteCount; 5] = - [READS_ONLY, READ_LEANING, BALANCED, WRITE_LEANING, WRITES_ONLY]; +const READ_WRITE_COUNTS: [ReadWriteCount; 5] = [ + READS_ONLY, + READ_LEANING, + BALANCED, + WRITE_LEANING, + WRITES_ONLY, +]; /// Benchmarks a repeated allocate/[X writes]/[Y reads]/deallocate workflow across /// the default number of threads and shards.
diff --git a/nearby/util/handle_map/src/declare_handle_map.rs b/common/handle_map/src/declare_handle_map.rs similarity index 97% rename from nearby/util/handle_map/src/declare_handle_map.rs rename to common/handle_map/src/declare_handle_map.rs index 688ec18..89078fa 100644 --- a/nearby/util/handle_map/src/declare_handle_map.rs +++ b/common/handle_map/src/declare_handle_map.rs
@@ -110,6 +110,10 @@ $crate::HandleMap::with_dimensions($map_dimension_provider); } + pub (crate) fn get_current_allocation_count() -> u32 { + GLOBAL_HANDLE_MAP.get_current_allocation_count() + } + #[doc = ::core::concat!( "A `#[repr(C)]` handle to a value of type `", ::core::stringify!($wrapped_type), "`."
diff --git a/nearby/util/handle_map/src/guard.rs b/common/handle_map/src/guard.rs similarity index 92% rename from nearby/util/handle_map/src/guard.rs rename to common/handle_map/src/guard.rs index 0c8c9d7..67d9787 100644 --- a/nearby/util/handle_map/src/guard.rs +++ b/common/handle_map/src/guard.rs
@@ -14,7 +14,7 @@ use crate::Handle; use core::ops::{Deref, DerefMut}; -use lock_adapter::std::RwMapping; +use lock_adapter::stdlib::RwMapping; use std::collections::HashMap; use std::marker::PhantomData; @@ -23,7 +23,7 @@ /// dropped, the underlying read lock on the associated /// shard will be dropped. pub struct ObjectReadGuardImpl<'a, T: 'a> { - pub(crate) guard: lock_adapter::std::MappedRwLockReadGuard< + pub(crate) guard: lock_adapter::stdlib::MappedRwLockReadGuard< 'a, <Self as ObjectReadGuard>::Arg, <Self as ObjectReadGuard>::Ret, @@ -81,7 +81,7 @@ /// dropped, the underlying read-write lock on the associated /// shard will be dropped. pub struct ObjectReadWriteGuardImpl<'a, T: 'a> { - pub(crate) guard: lock_adapter::std::MappedRwLockWriteGuard< + pub(crate) guard: lock_adapter::stdlib::MappedRwLockWriteGuard< 'a, <Self as ObjectReadWriteGuard>::Arg, <Self as ObjectReadWriteGuard>::Ret, @@ -131,11 +131,13 @@ fn map<'b>(&self, arg: &'b Self::Arg) -> &'b Self::Ret { #[allow(clippy::expect_used)] - arg.get(&self.handle).expect("Caller must verify that provided hande exists") + arg.get(&self.handle) + .expect("Caller must verify that provided hande exists") } fn map_mut<'b>(&self, arg: &'b mut Self::Arg) -> &'b mut Self::Ret { #[allow(clippy::expect_used)] - arg.get_mut(&self.handle).expect("Caller must verify that provided hande exists") + arg.get_mut(&self.handle) + .expect("Caller must verify that provided hande exists") } }
diff --git a/nearby/util/handle_map/src/lib.rs b/common/handle_map/src/lib.rs similarity index 94% rename from nearby/util/handle_map/src/lib.rs rename to common/handle_map/src/lib.rs index 22009c1..72bb78a 100644 --- a/nearby/util/handle_map/src/lib.rs +++ b/common/handle_map/src/lib.rs
@@ -16,9 +16,7 @@ //! a safer alternative to raw pointers for FFI interop. use core::fmt::Debug; -use std::boxed::Box; use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; -use std::vec::Vec; pub mod declare_handle_map; mod guard; @@ -159,21 +157,23 @@ initial_value_provider: impl FnOnce() -> T, ) -> Result<Handle, HandleMapFullError> { let wrapped_value_provider = move || Ok(initial_value_provider()); - self.try_allocate::<core::convert::Infallible>(wrapped_value_provider).map_err( - |e| match e { + self.try_allocate::<core::convert::Infallible>(wrapped_value_provider) + .map_err(|e| match e { HandleMapTryAllocateError::ValueProviderFailed(never) => match never {}, HandleMapTryAllocateError::HandleMapFull => HandleMapFullError, - }, - ) + }) } /// Attempts to allocate a new object within the given handle-map, returning - /// a handle to the location it was stored at. This operation - /// may fail if attempting to allocate over the `dimensions.max_active_handles` - /// limit imposed on the handle-map, in which case this method - /// will return a `HandleMapTryAllocateError::HandleMapFull`, - /// or if the passed initial-value provider fails, in which case this - /// will return the error wrapped in `HandleMapTryAllocateError::ValueProviderFailed`. + /// a handle to the location it was stored at. + /// + /// This operation may fail if attempting to allocate over the `dimensions.max_active_handles` + /// limit imposed on the handle-map, in which case this method will return a + /// `HandleMapTryAllocateError::HandleMapFull` and the given `initial_value_provider` will not + /// be run. + /// + /// The passed initial-value provider may also fail, in which case this will return the error + /// wrapped in `HandleMapTryAllocateError::ValueProviderFailed`. /// /// If your initial-value provider is infallible, see [`Self::allocate`] instead. pub fn try_allocate<E: Debug>( @@ -257,10 +257,8 @@ } /// Gets the actual number of elements stored in the entire map. - /// Only suitable for single-threaded sections of tests. - #[cfg(test)] - pub(crate) fn len(&self) -> usize { - self.handle_map_shards.iter().map(|s| s.len()).sum() + pub fn get_current_allocation_count(&self) -> u32 { + self.outstanding_allocations_counter.load(Ordering::Relaxed) } /// Sets the new-handle-id counter to the given value.
diff --git a/nearby/util/handle_map/src/shard.rs b/common/handle_map/src/shard.rs similarity index 91% rename from nearby/util/handle_map/src/shard.rs rename to common/handle_map/src/shard.rs index e5aad2f..c7cf509 100644 --- a/nearby/util/handle_map/src/shard.rs +++ b/common/handle_map/src/shard.rs
@@ -13,7 +13,7 @@ // limitations under the License. use core::ops::{Deref, DerefMut}; -use lock_adapter::std::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use lock_adapter::stdlib::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use lock_adapter::RwLock as _; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::HashMap; @@ -52,7 +52,9 @@ impl<T: Send + Sync> Default for HandleMapShard<T> { fn default() -> Self { - Self { data: RwLock::new(HashMap::new()) } + Self { + data: RwLock::new(HashMap::new()), + } } } @@ -63,9 +65,14 @@ if read_only_map_ref.contains_key(&handle) { let object_read_guard = ShardReadGuard::<T>::map( map_read_guard, - ObjectReadGuardMapping { handle, _marker: PhantomData }, + ObjectReadGuardMapping { + handle, + _marker: PhantomData, + }, ); - Ok(ObjectReadGuardImpl { guard: object_read_guard }) + Ok(ObjectReadGuardImpl { + guard: object_read_guard, + }) } else { // Auto-drop the read guard, and return an error Err(HandleNotPresentError) @@ -102,9 +109,14 @@ // Expose only the pointed-to object with a mapped read-write guard let object_read_write_guard = ShardReadWriteGuard::<T>::map( map_read_write_guard, - ObjectReadWriteGuardMapping { handle, _marker: PhantomData }, + ObjectReadWriteGuardMapping { + handle, + _marker: PhantomData, + }, ); - Ok(ObjectReadWriteGuardImpl { guard: object_read_write_guard }) + Ok(ObjectReadWriteGuardImpl { + guard: object_read_write_guard, + }) } pub fn deallocate( @@ -188,11 +200,4 @@ } } } - /// Gets the actual number of elements stored in this shard. - /// Only suitable for single-threaded sections of tests. - #[cfg(test)] - pub fn len(&self) -> usize { - let guard = ShardReadWriteLock::<T>::read(&self.data); - guard.deref().len() - } }
diff --git a/nearby/util/handle_map/src/tests.rs b/common/handle_map/src/tests.rs similarity index 80% rename from nearby/util/handle_map/src/tests.rs rename to common/handle_map/src/tests.rs index 90e773a..658b55d 100644 --- a/nearby/util/handle_map/src/tests.rs +++ b/common/handle_map/src/tests.rs
@@ -34,8 +34,10 @@ // Deliberately picking a higher number of threads. const NUM_ACTIVE_THREADS: u32 = 8; -const DEFAULT_DIMENSIONS: HandleMapDimensions = - HandleMapDimensions { num_shards: NUM_SHARDS, max_active_handles: MAX_ACTIVE_HANDLES }; +const DEFAULT_DIMENSIONS: HandleMapDimensions = HandleMapDimensions { + num_shards: NUM_SHARDS, + max_active_handles: MAX_ACTIVE_HANDLES, +}; fn build_handle_map<T: Send + Sync>() -> HandleMap<T> { HandleMap::with_dimensions(DEFAULT_DIMENSIONS) @@ -67,7 +69,9 @@ fn test_read_consistency_same_address() { let num_repetitions_per_thread = 10000; let handle_map = build_handle_map::<String>(); - let handle = handle_map.allocate(|| "hello".to_string()).expect("Allocation shouldn't fail"); + let handle = handle_map + .allocate(|| "hello".to_string()) + .expect("Allocation shouldn't fail"); let test_fn = Arc::new(move || { let value_ref = handle_map.get(handle).expect("Getting shouldn't fail"); assert_eq!("hello", value_ref.deref()); @@ -92,8 +96,8 @@ }); test_for_each_thread(test_fn, num_repetitions_per_thread); - let actual_num_active_handles = handle_map_post_function_ref.len(); - assert_eq!(MAX_ACTIVE_HANDLES as usize, actual_num_active_handles); + let actual_num_active_handles = handle_map_post_function_ref.get_current_allocation_count(); + assert_eq!(MAX_ACTIVE_HANDLES, actual_num_active_handles); } /// Tests deallocations and allocations near the allocation limit. @@ -122,8 +126,8 @@ // No matter what happened above, we should have the same number // of handles as when we started, because every successful allocation // should have been paired with a successful deallocation. - let actual_num_active_handles = handle_map_post_function_ref.len(); - assert_eq!((MAX_ACTIVE_HANDLES - 1) as usize, actual_num_active_handles); + let actual_num_active_handles = handle_map_post_function_ref.get_current_allocation_count(); + assert_eq!(MAX_ACTIVE_HANDLES - 1, actual_num_active_handles); //Verify that we still have space for one more entry after all that. let _ = handle_map_post_function_ref.allocate(|| 0xEE).unwrap(); @@ -136,15 +140,19 @@ let num_repetitions_per_thread = 10000; let handle_map = build_handle_map::<String>(); let test_fn = Arc::new(move || { - let handle = - handle_map.allocate(|| "Hello".to_string()).expect("Allocation shouldn't fail"); + let handle = handle_map + .allocate(|| "Hello".to_string()) + .expect("Allocation shouldn't fail"); { - let value_ref = handle_map.get(handle).expect("Getting the value shouldn't fail"); + let value_ref = handle_map + .get(handle) + .expect("Getting the value shouldn't fail"); assert_eq!("Hello", &*value_ref); }; { - let mut value_mut_ref = - handle_map.get_mut(handle).expect("Mutating the value shouldn't fail"); + let mut value_mut_ref = handle_map + .get_mut(handle) + .expect("Mutating the value shouldn't fail"); value_mut_ref.deref_mut().push_str(" World!"); }; { @@ -153,7 +161,9 @@ .expect("Getting the value after modification shouldn't fail"); assert_eq!("Hello World!", &*value_ref); }; - let removed = handle_map.deallocate(handle).expect("Deallocation shouldn't fail"); + let removed = handle_map + .deallocate(handle) + .expect("Deallocation shouldn't fail"); assert_eq!("Hello World!", removed); }); test_for_each_thread(test_fn, num_repetitions_per_thread); @@ -175,8 +185,9 @@ let join_handle_a = thread::spawn(move || { for i in 1..num_repetitions_per_thread { { - let value_ref = - handle_map.get(handle).expect("Getting the value from thread A shouldn't fail"); + let value_ref = handle_map + .get(handle) + .expect("Getting the value from thread A shouldn't fail"); let value = &value_ref.0; assert_eq!(i, value.len()); } @@ -221,7 +232,9 @@ let num_repetitions_per_thread = 100; let mut handle_map = build_handle_map::<u8>(); for _ in 0..(num_repetitions_per_thread * NUM_ACTIVE_THREADS) { - let handle = handle_map.allocate(|| 0xFF).expect("Initial allocations shouldn't fail"); + let handle = handle_map + .allocate(|| 0xFF) + .expect("Initial allocations shouldn't fail"); let _ = all_handles.insert(handle); } // Reset the new-handle-id counter @@ -245,7 +258,9 @@ thread_handles.push(thread_handle); } for thread_handle in thread_handles { - let handles: Vec<Handle> = thread_handle.join().expect("Individual threads shouldn't fail"); + let handles: Vec<Handle> = thread_handle + .join() + .expect("Individual threads shouldn't fail"); for handle in handles { let was_distinct = all_handles.insert(handle); assert!(was_distinct); @@ -257,16 +272,23 @@ fn test_id_wraparound() { let mut handle_map = build_handle_map::<u8>(); handle_map.set_new_handle_id_counter(u64::MAX); - let _ = handle_map.allocate(|| 0xAB).expect("Counter wrap-around allocation should not fail"); - let _ = - handle_map.allocate(|| 0xCD).expect("Post-counter-wrap-around allocation should not fail"); + let _ = handle_map + .allocate(|| 0xAB) + .expect("Counter wrap-around allocation should not fail"); + let _ = handle_map + .allocate(|| 0xCD) + .expect("Post-counter-wrap-around allocation should not fail"); } #[test] fn test_deallocate_unallocated_handle() { let handle_map = build_handle_map::<usize>(); - let handle = handle_map.allocate(|| 2).expect("Allocation shouldn't fail"); - let deallocated = handle_map.deallocate(handle).expect("Deallocation shouldn't fail"); + let handle = handle_map + .allocate(|| 2) + .expect("Allocation shouldn't fail"); + let deallocated = handle_map + .deallocate(handle) + .expect("Deallocation shouldn't fail"); assert_eq!(2, deallocated); let double_deallocate_result = handle_map.deallocate(handle); assert!(double_deallocate_result.is_err()); @@ -275,8 +297,12 @@ #[test] fn test_get_unallocated_handle() { let handle_map = build_handle_map::<u8>(); - let handle = handle_map.allocate(|| 0xFE).expect("Allocation shouldn't fail"); - let deallocated = handle_map.deallocate(handle).expect("Deallocation shouldn't fail"); + let handle = handle_map + .allocate(|| 0xFE) + .expect("Allocation shouldn't fail"); + let deallocated = handle_map + .deallocate(handle) + .expect("Deallocation shouldn't fail"); assert_eq!(0xFE, deallocated); let read_result = handle_map.get(handle); assert!(read_result.is_err()); @@ -285,8 +311,12 @@ #[test] fn test_get_mut_unallocated_handle() { let handle_map = build_handle_map::<(usize, usize, usize)>(); - let handle = handle_map.allocate(|| (1, 2, 3)).expect("Allocation shouldn't fail"); - let deallocated = handle_map.deallocate(handle).expect("Deallocation shouldn't fail"); + let handle = handle_map + .allocate(|| (1, 2, 3)) + .expect("Allocation shouldn't fail"); + let deallocated = handle_map + .deallocate(handle) + .expect("Deallocation shouldn't fail"); assert_eq!((1, 2, 3), deallocated); let get_mut_result = handle_map.get_mut(handle); assert!(get_mut_result.is_err());
diff --git a/nearby/util/lock_adapter/Cargo.toml b/common/lock_adapter/Cargo.toml similarity index 100% rename from nearby/util/lock_adapter/Cargo.toml rename to common/lock_adapter/Cargo.toml
diff --git a/nearby/util/lock_adapter/src/lib.rs b/common/lock_adapter/src/lib.rs similarity index 97% rename from nearby/util/lock_adapter/src/lib.rs rename to common/lock_adapter/src/lib.rs index 6bf6f0f..1c77ee8 100644 --- a/nearby/util/lock_adapter/src/lib.rs +++ b/common/lock_adapter/src/lib.rs
@@ -15,7 +15,10 @@ //! An abstraction layer for Rust synchronization primitives which provides both no_std and std library //! based implementations -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] + +#[cfg(feature = "std")] +extern crate std; /// A Spinlock-based implementation of Mutex using the `spin` crate that can be used in `no_std` /// environments. @@ -28,7 +31,7 @@ /// /// Available with the feature `std`. #[cfg(feature = "std")] -pub mod std; +pub mod stdlib; /// A trait for mutex implementations that doesn't support poisoning. If the thread panicked while /// holding the mutex, the data will be released normally (as spin::Mutex would).
diff --git a/nearby/util/lock_adapter/src/spin.rs b/common/lock_adapter/src/spin.rs similarity index 100% rename from nearby/util/lock_adapter/src/spin.rs rename to common/lock_adapter/src/spin.rs
diff --git a/nearby/util/lock_adapter/src/std.rs b/common/lock_adapter/src/stdlib.rs similarity index 100% rename from nearby/util/lock_adapter/src/std.rs rename to common/lock_adapter/src/stdlib.rs
diff --git a/nearby/util/pourover/Cargo.toml b/common/pourover/Cargo.toml similarity index 64% rename from nearby/util/pourover/Cargo.toml rename to common/pourover/Cargo.toml index ce6fefa..eb03cdb 100644 --- a/nearby/util/pourover/Cargo.toml +++ b/common/pourover/Cargo.toml
@@ -4,6 +4,12 @@ edition.workspace = true publish.workspace = true +[lints] +workspace = true +# Needed for FFI, but cannot be overidden in this file. Usages will be marked +# with `#[allow(unsafe_code)]`. +# rust.unsafe_code = "allow" + [dependencies] jni.workspace = true pourover_macro.workspace = true
diff --git a/nearby/util/pourover/src/conversions.rs b/common/pourover/src/conversions.rs similarity index 97% rename from nearby/util/pourover/src/conversions.rs rename to common/pourover/src/conversions.rs index 69a00a2..e311e6d 100644 --- a/nearby/util/pourover/src/conversions.rs +++ b/common/pourover/src/conversions.rs
@@ -26,6 +26,7 @@ impl<'a> ToSigned for &'a [u8] { type Signed = &'a [i8]; + #[allow(unsafe_code)] fn to_signed(self) -> Self::Signed { let len = self.len(); // Safety: @@ -46,6 +47,7 @@ impl<'a> ToUnsigned for &'a [i8] { type Unsigned = &'a [u8]; + #[allow(unsafe_code)] fn to_unsigned(self) -> Self::Unsigned { let len = self.len(); // Safety:
diff --git a/nearby/util/pourover/src/desc.rs b/common/pourover/src/desc.rs similarity index 96% rename from nearby/util/pourover/src/desc.rs rename to common/pourover/src/desc.rs index 507d3de..26bada6 100644 --- a/nearby/util/pourover/src/desc.rs +++ b/common/pourover/src/desc.rs
@@ -35,7 +35,8 @@ //! static MY_CLASS_GET_BAR_METHOD: MethodDesc = MY_CLASS_DESC.method("getBar", "I()"); //! ``` -use core::convert::AsRef; +#![allow(unsafe_code)] + use jni::{ descriptors::Desc, objects::{GlobalRef, JClass, JFieldID, JMethodID, JObject, JStaticFieldID, JStaticMethodID}, @@ -57,7 +58,10 @@ impl ClassDesc { /// Create a new descriptor with the given JNI descriptor string. pub const fn new(descriptor: &'static str) -> Self { - Self { descriptor, cls: RwLock::new(None) } + Self { + descriptor, + cls: RwLock::new(None), + } } /// Create a new descriptor for a field member of this class. @@ -139,7 +143,11 @@ impl<'lock> AsRef<JClass<'static>> for CachedClass<'lock> { fn as_ref(&self) -> &JClass<'static> { // `unwrap` is valid since we checked for `Some` in the constructor. - let global = self.0.as_ref().unwrap(); + #[allow(clippy::expect_used)] + let global = self + .0 + .as_ref() + .expect("Created CachedClass in an invalid state"); // No direct conversion to JClass, so let's go through JObject first. let obj: &JObject<'static> = global.as_ref(); // This assumes our object is a class object. @@ -181,6 +189,7 @@ // Safe to unwrap since we just set `self.cls` to `Some`. `ClassDesc::free` can't be called // before this point because it takes a mutable reference to `*self`. + #[allow(clippy::unwrap_used)] Ok(self.get_cached().unwrap()) } } @@ -209,7 +218,12 @@ /// /// Please use the helpers on [`ClassDesc`] instead of directly calling this method. pub const fn new(cls: &'cls ClassDesc, name: &'static str, sig: &'static str) -> Self { - Self { cls, name, sig, id: RwLock::new(None) } + Self { + cls, + name, + sig, + id: RwLock::new(None), + } } /// Get the class descriptor that this member is associated to. @@ -248,6 +262,7 @@ Ok(id) } else { // Can unwrap since we just checked for `None`. + #[allow(clippy::unwrap_used)] Ok(*guard.as_ref().unwrap()) } }
diff --git a/nearby/util/pourover/src/lib.rs b/common/pourover/src/lib.rs similarity index 85% rename from nearby/util/pourover/src/lib.rs rename to common/pourover/src/lib.rs index 51495de..ed861ea 100644 --- a/nearby/util/pourover/src/lib.rs +++ b/common/pourover/src/lib.rs
@@ -14,11 +14,7 @@ //! Utilties for JNI interactions. -// Enforce documentation -#![deny(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn)] - -pub use pourover_macro::jni_method; +pub use pourover_macro::{call_constructor, call_method, call_static_method, jni_method}; pub mod desc;
diff --git a/nearby/util/pourover/tests/Foo.java b/common/pourover/tests/Foo.java similarity index 95% rename from nearby/util/pourover/tests/Foo.java rename to common/pourover/tests/Foo.java index 0907964..eb76e9b 100644 --- a/nearby/util/pourover/tests/Foo.java +++ b/common/pourover/tests/Foo.java
@@ -31,6 +31,10 @@ this.foo = f; } + public int getFoo() { + return foo; + } + public boolean mfoo() { return true; }
diff --git a/common/pourover/tests/call_method_integration.rs b/common/pourover/tests/call_method_integration.rs new file mode 100644 index 0000000..5de2547 --- /dev/null +++ b/common/pourover/tests/call_method_integration.rs
@@ -0,0 +1,48 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{objects::JObject, JavaVM}; +use std::error::Error; + +mod common; +use common::foo_class::*; + +#[test] +fn jni_access() -> Result<(), Box<dyn Error>> { + // Create the environment + let vm = JavaVM::new( + jni::InitArgsBuilder::new() + .version(jni::JNIVersion::V8) + .option("-Xcheck:jni") + .build()?, + )?; + let mut env = vm.attach_current_thread()?; + + // Load `Foo.class` + { + let foo_class = compile_foo()?; + let loaded_foo = env.define_class(CLASS_DESC, &JObject::null(), &foo_class)?; + env.delete_local_ref(loaded_foo)?; + } + + let foo_obj = pourover::call_constructor!(&mut env, &FOO, "(I)V", 123)?; + let inner_int = pourover::call_method!(&mut env, &FOO, "getFoo", "()I", &foo_obj)?; + assert_eq!(123, inner_int); + env.delete_local_ref(foo_obj)?; + + let static_int = pourover::call_static_method!(&mut env, &FOO, "smfoo", "()I")?; + assert_eq!(3, static_int); + + Ok(()) +}
diff --git a/nearby/util/pourover/tests/common/foo_class.rs b/common/pourover/tests/common/foo_class.rs similarity index 96% rename from nearby/util/pourover/tests/common/foo_class.rs rename to common/pourover/tests/common/foo_class.rs index 65971d7..3ded762 100644 --- a/nearby/util/pourover/tests/common/foo_class.rs +++ b/common/pourover/tests/common/foo_class.rs
@@ -41,7 +41,7 @@ /// stdout. #[test] fn has_java() -> Result<(), Box<dyn Error>> { - Command::new("java").arg("--version").status()?; + let _ = Command::new("java").arg("--version").status()?; Ok(()) } @@ -67,7 +67,7 @@ } // Compile Foo.java into the temp dir - Command::new("javac") + let _ = Command::new("javac") .args(["--release", "8"]) .arg("-d") .arg(&tmp)
diff --git a/nearby/util/pourover/tests/common/mod.rs b/common/pourover/tests/common/mod.rs similarity index 100% rename from nearby/util/pourover/tests/common/mod.rs rename to common/pourover/tests/common/mod.rs
diff --git a/nearby/util/pourover/tests/desc_integration.rs b/common/pourover/tests/desc_integration.rs similarity index 90% rename from nearby/util/pourover/tests/desc_integration.rs rename to common/pourover/tests/desc_integration.rs index 7eec528..dd330c3 100644 --- a/nearby/util/pourover/tests/desc_integration.rs +++ b/common/pourover/tests/desc_integration.rs
@@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(unsafe_code)] + use jni::{ descriptors::Desc, objects::JObject, @@ -27,7 +29,10 @@ fn jni_access() -> Result<(), Box<dyn Error>> { // Create the environment let vm = JavaVM::new( - jni::InitArgsBuilder::new().version(jni::JNIVersion::V8).option("-Xcheck:jni").build()?, + jni::InitArgsBuilder::new() + .version(jni::JNIVersion::V8) + .option("-Xcheck:jni") + .build()?, )?; let mut env = vm.attach_current_thread()?; @@ -52,8 +57,10 @@ // Verify we can access all of the members - let field_value = - { env.get_field_unchecked(&obj_foo, &FIELD, ReturnType::Primitive(Primitive::Int))?.i()? }; + let field_value = { + env.get_field_unchecked(&obj_foo, &FIELD, ReturnType::Primitive(Primitive::Int))? + .i()? + }; assert_eq!(123, field_value); let method_value = {
diff --git a/nearby/util/pourover/tests/jni_method_integration.rs b/common/pourover/tests/jni_method_integration.rs similarity index 95% rename from nearby/util/pourover/tests/jni_method_integration.rs rename to common/pourover/tests/jni_method_integration.rs index 73d89d1..4bd6547 100644 --- a/nearby/util/pourover/tests/jni_method_integration.rs +++ b/common/pourover/tests/jni_method_integration.rs
@@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(unsafe_code, clippy::unwrap_used, clippy::expect_used, clippy::panic)] + use jni::{ descriptors::Desc, objects::{JObject, JString}, @@ -69,10 +71,14 @@ fn can_call_native_method() -> Result<(), Box<dyn Error>> { // Create the environment let vm = JavaVM::new( - jni::InitArgsBuilder::new().version(jni::JNIVersion::V8).option("-Xcheck:jni").build()?, + jni::InitArgsBuilder::new() + .version(jni::JNIVersion::V8) + .option("-Xcheck:jni") + .build()?, )?; let mut env = vm.attach_current_thread()?; + // Load `Foo.class` { let foo_class = compile_foo()?; let loaded_foo = env.define_class(CLASS_DESC, &JObject::null(), &foo_class)?;
diff --git a/common/pourover_macro/Cargo.toml b/common/pourover_macro/Cargo.toml new file mode 100644 index 0000000..0473dd4 --- /dev/null +++ b/common/pourover_macro/Cargo.toml
@@ -0,0 +1,22 @@ +[package] +name = "pourover_macro" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[lints] +workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +syn.workspace = true +quote.workspace = true +nom = { workspace = true, features = ["alloc"] } +jni = { workspace = true, optional = true } + +[dev-dependencies] +pourover.workspace = true # doc only +jni.workspace = true # doc only
diff --git a/common/pourover_macro/src/call_method.rs b/common/pourover_macro/src/call_method.rs new file mode 100644 index 0000000..5886a86 --- /dev/null +++ b/common/pourover_macro/src/call_method.rs
@@ -0,0 +1,100 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Implementation of the `call_method!` series of macros. These macros are meant to be used as +//! function-like macros and implement a statically type-safe way to call Java methods while also +//! caching the method id. The macro arguments are implemented in [`mod ast`](mod@ast) and the +//! generated code is implemented in [`mod codegen`](mod@codegen). + +use proc_macro2::TokenStream; +use syn::parse_quote; + +use ast::{ConstructorArgs, InstanceArgs, StaticArgs}; +use codegen::{MethodCall, MethodInfo, Receiver}; + +mod ast; +mod codegen; + +/// See [`crate::call_method!`] for usage. +pub fn call_method(args: TokenStream) -> syn::Result<TokenStream> { + let args = syn::parse2::<InstanceArgs>(args)?; + + let method_info = MethodInfo::new(args.cls, args.name, args.sig); + let receiver = Receiver::Instance(args.this); + let method_call = MethodCall::new( + args.env, + method_info, + receiver, + args.args.into_iter().collect(), + ); + + method_call.generate().map_err(syn::Error::from) +} + +/// See [`crate::call_static_method!`] for usage. +pub fn call_static_method(args: TokenStream) -> syn::Result<TokenStream> { + let args = syn::parse2::<StaticArgs>(args)?; + + let method_info = MethodInfo::new(args.cls, args.name, args.sig); + let receiver = Receiver::Static; + let method_call = MethodCall::new( + args.env, + method_info, + receiver, + args.args.into_iter().collect(), + ); + + method_call.generate().map_err(syn::Error::from) +} + +/// See [`crate::call_constructor!`] for usage. +pub fn call_constructor(args: TokenStream) -> syn::Result<TokenStream> { + let args = syn::parse2::<ConstructorArgs>(args)?; + + let name = parse_quote!["<init>"]; + let method_info = MethodInfo::new(args.cls, name, args.sig); + let receiver = Receiver::Constructor; + let method_call = MethodCall::new( + args.env, + method_info, + receiver, + args.args.into_iter().collect(), + ); + + method_call.generate().map_err(syn::Error::from) +} + +#[cfg(test)] +mod test { + use super::*; + use quote::quote; + + #[test] + fn call_method_error() { + let out = call_method(quote![&mut env, &CLS, "method", "INVALID", &this_obj]); + assert!(out.is_err()); + } + + #[test] + fn call_static_method_error() { + let out = call_static_method(quote![&mut env, &CLS, "method", "INVALID"]); + assert!(out.is_err()); + } + + #[test] + fn call_constructor_error() { + let out = call_constructor(quote![&mut env, &CLS, "INVALID"]); + assert!(out.is_err()); + } +}
diff --git a/common/pourover_macro/src/call_method/ast.rs b/common/pourover_macro/src/call_method/ast.rs new file mode 100644 index 0000000..c5e66f9 --- /dev/null +++ b/common/pourover_macro/src/call_method/ast.rs
@@ -0,0 +1,290 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Syntax trees for the arguments to the `call_method!` series of proc macros. + +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + Expr, LitStr, Token, +}; + +/// The trailing method arguments +type Args = Punctuated<Expr, Token![,]>; + +/// See [`crate::call_constructor!`]. +pub struct ConstructorArgs { + pub env: Expr, + pub cls: Expr, + pub sig: LitStr, + pub args: Args, +} + +impl Parse for ConstructorArgs { + fn parse(stream: ParseStream<'_>) -> syn::Result<Self> { + let env = CommaSep::parse(stream)?.node; + let cls = CommaSep::parse(stream)?.node; + let sig = stream.parse()?; + let args = parse_args(stream)?; + + Ok(Self { + env, + cls, + sig, + args, + }) + } +} + +/// See [`crate::call_static_method!`]. +pub struct StaticArgs { + pub env: Expr, + pub cls: Expr, + pub name: Expr, + pub sig: LitStr, + pub args: Args, +} + +impl Parse for StaticArgs { + fn parse(stream: ParseStream<'_>) -> syn::Result<Self> { + let env = CommaSep::parse(stream)?.node; + let cls = CommaSep::parse(stream)?.node; + let name = CommaSep::parse(stream)?.node; + let sig = stream.parse()?; + let args = parse_args(stream)?; + + Ok(Self { + env, + cls, + name, + sig, + args, + }) + } +} + +/// See [`crate::call_method!`]. +pub struct InstanceArgs { + pub env: Expr, + pub cls: Expr, + pub name: Expr, + pub sig: LitStr, + pub this: Expr, + pub args: Args, +} + +impl Parse for InstanceArgs { + fn parse(stream: ParseStream<'_>) -> syn::Result<Self> { + let env = CommaSep::parse(stream)?.node; + let cls = CommaSep::parse(stream)?.node; + let name = CommaSep::parse(stream)?.node; + let sig = CommaSep::parse(stream)?.node; + let this = stream.parse()?; + let args = parse_args(stream)?; + + Ok(Self { + env, + cls, + name, + sig, + this, + args, + }) + } +} + +/// Parses the variable number of arguments to the method. A leading comma is required when there +/// are arguments being passed. +fn parse_args(stream: ParseStream<'_>) -> syn::Result<Args> { + Ok(if stream.is_empty() { + Punctuated::new() + } else { + let _ = stream.parse::<Token![,]>()?; + Punctuated::parse_terminated(stream)? + }) +} + +/// A syntax node followed by a comma. +#[allow(dead_code)] +pub struct CommaSep<T> { + pub node: T, + pub comma: Token![,], +} + +impl<T: Parse> Parse for CommaSep<T> { + fn parse(stream: ParseStream<'_>) -> syn::Result<Self> { + Ok(Self { + node: stream.parse()?, + comma: stream.parse()?, + }) + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod test { + use super::*; + use quote::quote; + use syn::parse::Parser; + + #[test] + fn comma_sep_correct() { + let ret: CommaSep<syn::Ident> = syn::parse2(quote![abc,]).unwrap(); + + assert_eq!(ret.node, "abc"); + } + + #[test] + fn comma_sep_incorrect() { + assert!(syn::parse2::<CommaSep<syn::Ident>>(quote![abc]).is_err()); + assert!(syn::parse2::<CommaSep<syn::Ident>>(quote![,abc]).is_err()); + assert!(syn::parse2::<CommaSep<syn::Ident>>(quote![,]).is_err()); + } + + #[test] + fn parse_args_no_args() { + let args = parse_args.parse2(quote![]).unwrap(); + + assert_eq!(0, args.len()); + } + + #[test] + fn parse_args_no_args_extra_comma() { + let args = parse_args.parse2(quote![,]).unwrap(); + + assert_eq!(0, args.len()); + } + + #[test] + fn parse_args_single_no_trailing() { + let args = parse_args.parse2(quote![, foo]).unwrap(); + + assert_eq!(1, args.len()); + } + + #[test] + fn parse_args_single_trailing() { + let args = parse_args.parse2(quote![, foo,]).unwrap(); + + assert_eq!(1, args.len()); + } + + #[test] + fn parse_args_multi_no_trailing() { + let args = parse_args.parse2(quote![, one, two, three]).unwrap(); + + assert_eq!(3, args.len()); + } + + #[test] + fn parse_args_multi_trailing() { + let args = parse_args.parse2(quote![, one, two, three,]).unwrap(); + + assert_eq!(3, args.len()); + } + + #[test] + fn parse_args_error_two_commas() { + let res = parse_args.parse2(quote![, ,]); + + assert!(res.is_err()); + } + + #[test] + fn parse_constructor_args() { + let tests = [ + quote![&mut env, &CLS, "()V"], + quote![&mut env, &CLS, "()V",], + quote![&mut env, &CLS, "(I)V", 123], + quote![&mut env, &CLS, "(I)V", 123,], + quote![&mut env, &CLS, "(ILjava/lang/String;)V", 123, &some_str], + quote![&mut env, &CLS, "(ILjava/lang/String;)V", 123, &some_str,], + ]; + + for valid in tests { + assert!( + syn::parse2::<ConstructorArgs>(valid.clone()).is_ok(), + "test: {valid}" + ); + } + } + + #[test] + fn parse_static_method_args() { + let tests = [ + quote![&mut env, &CLS, "methodName", "()V"], + quote![&mut env, &CLS, "methodName", "()V",], + quote![&mut env, &CLS, "methodName", "(I)V", 123], + quote![&mut env, &CLS, "methodName", "(I)V", 123,], + quote![ + &mut env, + &CLS, + "methodName", + "(ILjava/lang/String;)V", + 123, + &some_str + ], + quote![ + &mut env, + &CLS, + "methodName", + "(ILjava/lang/String;)V", + 123, + &some_str, + ], + ]; + + for valid in tests { + assert!( + syn::parse2::<StaticArgs>(valid.clone()).is_ok(), + "test: {valid}" + ); + } + } + + #[test] + fn parse_method_args() { + let tests = [ + quote![&mut env, &CLS, "methodName", "()V", &this_obj], + quote![&mut env, &CLS, "methodName", "()V", &this_obj,], + quote![&mut env, &CLS, "methodName", "(I)V", &this_obj, 123], + quote![&mut env, &CLS, "methodName", "(I)V", &this_obj, 123,], + quote![ + &mut env, + &CLS, + "methodName", + "(ILjava/lang/String;)V", + &this_obj, + 123, + &some_str + ], + quote![ + &mut env, + &CLS, + "methodName", + "(ILjava/lang/String;)V", + &this_obj, + 123, + &some_str, + ], + ]; + + for valid in tests { + assert!( + syn::parse2::<InstanceArgs>(valid.clone()).is_ok(), + "test: {valid}" + ); + } + } +}
diff --git a/common/pourover_macro/src/call_method/codegen.rs b/common/pourover_macro/src/call_method/codegen.rs new file mode 100644 index 0000000..bce3976 --- /dev/null +++ b/common/pourover_macro/src/call_method/codegen.rs
@@ -0,0 +1,610 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Code generation for the `call_method!` series of proc-macros. This module is used by creating a +//! [`MethodCall`] instance and calling [`MethodCall::generate`]. The generated code will vary +//! for each macro based on the contained [`Receiver`] value. If there is a detected issue with the +//! [`MethodCall`] provided, then `generate` will return a [`CodegenError`] with information on +//! what is wrong. This error can be converted into a [`syn::Error`] for reporting any failures to +//! the user. + +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned, TokenStreamExt}; +use syn::{parse_quote, spanned::Spanned, Expr, Ident, ItemStatic, LitStr, Type}; + +use crate::type_parser::{JavaType, MethodSig, NonArray, Primitive, ReturnType}; + +/// The errors that can be encountered during codegen. Used in [`CodegenError`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ErrorKind { + InvalidArgsLength { expected: usize, found: usize }, + ConstructorRetValShouldBeVoid, + InvalidTypeSignature, +} + +/// An error encountered during codegen with span information. Can be converted to [`syn::Error`]. +/// using [`From`]. +#[derive(Clone, Debug)] +pub struct CodegenError(pub Span, pub ErrorKind); + +impl From<CodegenError> for syn::Error { + fn from(CodegenError(span, kind): CodegenError) -> syn::Error { + use ErrorKind::*; + match kind { + InvalidArgsLength { expected, found } => { + syn::Error::new(span, format!("The number of args does not match the type signature provided: expected={expected}, found={found}")) + } + ConstructorRetValShouldBeVoid => { + syn::Error::new(span, "Return type should be `void` (`V`) for constructor methods") + } + InvalidTypeSignature => syn::Error::new(span, "Failed to parse type signature"), + } + } +} + +/// Codegen can fail with [`CodegenError`]. +pub type CodegenResult<T> = Result<T, CodegenError>; + +/// Describes a method that will be generated. Create one with [`MethodCall::new`] and generate +/// code with [`MethodCall::generate`]. This should be given AST nodes from the macro input so that +/// errors are associated properly to the input span. +pub struct MethodCall { + env: Expr, + method: MethodInfo, + receiver: Receiver, + arg_exprs: Vec<Expr>, +} + +impl MethodCall { + /// Create a new MethodCall instance + pub fn new(env: Expr, method: MethodInfo, receiver: Receiver, arg_exprs: Vec<Expr>) -> Self { + Self { + env, + method, + receiver, + arg_exprs, + } + } + + /// Generate code to call the described method. + pub fn generate(&self) -> CodegenResult<TokenStream> { + // Needs to be threaded manually to other methods since self-referential structs can't + // exist. + let sig = self.method.sig()?; + + let args = self.generate_args(&sig)?; + + let method_call = self + .receiver + .generate_call(&self.env, &self.method, &sig, &args)?; + + // Wrap the generated code in a closure so that we can access the outer scope but any + // variables we define aren't accessible by the outer scope. There is small hygiene issue + // where the arg exprs have our `env` variable in scope. If this becomes an issue we can + // refactor these exprs to be passed as closure parameters instead. + Ok(quote! { + (|| { + #method_call + })() + }) + } + + /// Generate the `&[jni::jvalue]` arguments slice that will be passed to the `jni` method call. + /// This validates the argument count and types. + fn generate_args(&self, sig: &MethodSig<'_>) -> CodegenResult<Expr> { + // Safety: must check that arg count matches the signature + if self.arg_exprs.len() != sig.args.len() { + return Err(CodegenError( + self.method.sig.span(), + ErrorKind::InvalidArgsLength { + expected: sig.args.len(), + found: self.arg_exprs.len(), + }, + )); + } + + // Create each `jvalue` expression + let type_expr_pairs = core::iter::zip(sig.args.iter().copied(), self.arg_exprs.iter()); + let jvalues = type_expr_pairs.map(|(ty, expr)| generate_jvalue(ty, expr)); + + // Put the `jvalue` expressions in a slice. + Ok(parse_quote! { + &[#(#jvalues),*] + }) + } +} + +/// The receiver of the method call and the type of the method. +pub enum Receiver { + /// A constructor. + Constructor, + /// A static method. + Static, + /// An instance method. The `Expr` here is the `this` object. + Instance(Expr), +} + +impl Receiver { + /// Generate the code that performs the JNI call. + fn generate_call( + &self, + env: &Expr, + method_info: &MethodInfo, + sig: &MethodSig<'_>, + args: &Expr, + ) -> CodegenResult<TokenStream> { + // Constructors are void methods. Validate this fact. + if matches!(*self, Receiver::Constructor) && !sig.ret.is_void() { + return Err(CodegenError( + method_info.sig.span(), + ErrorKind::ConstructorRetValShouldBeVoid, + )); + } + + // The static item containing the `pourover::[Static]MethodDesc`. + let method_desc = self.generate_method_desc(method_info); + + // The `jni::signature::ReturnType` that the `jni` crate uses to perform the correct native + // call. + let return_type = return_type_from_sig(sig.ret); + + // A conversion expression to convert from `jni::object::JValueOwned` to the actual return + // type. We have this information from the parsed method signature whereas the `jni` crate + // only knows this at runtime. + let conversion = return_value_conversion_from_sig(sig.ret); + + // This preamble is used to evaluate all the client-provided expressions outside of the + // `unsafe` block. This is the same for all receiver kinds. + let mut method_call = quote! { + #method_desc + + let env: &mut ::jni::JNIEnv = #env; + let method_id = ::jni::descriptors::Desc::lookup(&METHOD_DESC, env)?; + let args: &[::jni::sys::jvalue] = #args; + }; + + // Generate the unsafe JNI call. + // + // Safety: `args` contains the arguments to this method. The type signature of this + // method is `#sig`. + // + // `args` must adhere to the following: + // - `args.len()` must match the number of arguments given in the type signature. + // - The union value of each arg in `args` must match the type specified in the type + // signature. + // + // These conditions are upheld by this proc macro and a compile error will be caused if + // they are broken. No user-provided code is executed within the `unsafe` block. + method_call.append_all(match self { + Self::Constructor => quote! { + unsafe { + env.new_object_unchecked( + METHOD_DESC.cls(), + method_id, + args, + ) + } + }, + Self::Static => quote! { + unsafe { + env.call_static_method_unchecked( + METHOD_DESC.cls(), + method_id, + #return_type, + args, + ) + }#conversion + }, + Self::Instance(this) => quote! { + let this_obj: &JObject = #this; + unsafe { + env.call_method_unchecked( + this_obj, + method_id, + #return_type, + args, + ) + }#conversion + }, + }); + + Ok(method_call) + } + + fn generate_method_desc(&self, MethodInfo { cls, name, sig, .. }: &MethodInfo) -> ItemStatic { + match self { + Self::Constructor => parse_quote! { + static METHOD_DESC: ::pourover::desc::MethodDesc = (#cls).constructor(#sig); + }, + Self::Static => parse_quote! { + static METHOD_DESC: ::pourover::desc::StaticMethodDesc = (#cls).static_method(#name, #sig); + }, + Self::Instance(_) => parse_quote! { + static METHOD_DESC: ::pourover::desc::MethodDesc = (#cls).method(#name, #sig); + }, + } + } +} + +/// Information about the method being called +pub struct MethodInfo { + cls: Expr, + name: Expr, + sig: LitStr, + /// Derived from `sig.value()`. This string must be stored in the struct so that we can return + /// a `MethodSig` instance that references it from `MethodInfo::sig()`. + sig_str: String, +} + +impl MethodInfo { + pub fn new(cls: Expr, name: Expr, sig: LitStr) -> Self { + let sig_str = sig.value(); + Self { + cls, + name, + sig, + sig_str, + } + } + + /// Parse the type signature from `sig`. Will return a [`CodegenError`] if the signature cannot + /// be parsed. + fn sig(&self) -> CodegenResult<MethodSig<'_>> { + MethodSig::try_from_str(&self.sig_str) + .ok_or_else(|| CodegenError(self.sig.span(), ErrorKind::InvalidTypeSignature)) + } +} + +/// Generate a `jni::sys::jvalue` instance given a Java type and a Rust value. +/// +/// Safety: The generated `jvalue` must match the given type `ty`. +fn generate_jvalue(ty: JavaType<'_>, expr: &Expr) -> TokenStream { + // The `jvalue` field to inhabit + let union_field: Ident; + // The expected input type + let type_name: Type; + // Whether we need to call `JObject::as_raw()` on the input type + let needs_as_raw: bool; + + // Fill the above values based the type signature. + match ty { + JavaType::Array { depth, ty } => { + union_field = parse_quote![l]; + if let NonArray::Primitive(p) = ty { + if depth.get() == 1 { + let prim_type = prim_to_sys_type(p); + type_name = parse_quote![::jni::objects::JPrimitiveArray<'_, #prim_type>] + } else { + type_name = parse_quote![&::jni::objects::JObjectArray<'_>]; + } + } else { + type_name = parse_quote![&::jni::objects::JObjectArray<'_>]; + } + needs_as_raw = true; + } + JavaType::NonArray(NonArray::Object { cls }) => { + union_field = parse_quote![l]; + type_name = match cls { + "java/lang/String" => parse_quote![&::jni::objects::JString<'_>], + "java/util/List" => parse_quote![&::jni::objects::JList<'_>], + "java/util/Map" => parse_quote![&::jni::objects::JMap<'_>], + _ => parse_quote![&::jni::objects::JObject<'_>], + }; + needs_as_raw = true; + } + JavaType::NonArray(NonArray::Primitive(p)) => { + union_field = prim_to_union_field(p); + type_name = prim_to_sys_type(p); + needs_as_raw = false; + } + } + + // The as_raw() tokens if required. + let as_raw = if needs_as_raw { + quote! { .as_raw() } + } else { + quote![] + }; + + // Create the `jvalue` expression. This uses `identity` to produce nice type error messages. + quote_spanned! { expr.span() => + ::jni::sys::jvalue { + #union_field: ::core::convert::identity::<#type_name>(#expr) #as_raw + } + } +} + +/// Get a `::jni::signature::ReturnType` expression from a [`crate::type_parser::ReturnType`]. This +/// value is passed to the `jni` crate so that it knows which JNI method to call. +fn return_type_from_sig(ret: ReturnType<'_>) -> Expr { + let prim_type = |prim| parse_quote![::jni::signature::ReturnType::Primitive(::jni::signature::Primitive::#prim)]; + + use crate::type_parser::{JavaType::*, NonArray::*, Primitive::*}; + + match ret { + ReturnType::Void => prim_type(quote![Void]), + ReturnType::Returns(NonArray(Primitive(Boolean))) => prim_type(quote![Boolean]), + ReturnType::Returns(NonArray(Primitive(Byte))) => prim_type(quote![Byte]), + ReturnType::Returns(NonArray(Primitive(Char))) => prim_type(quote![Char]), + ReturnType::Returns(NonArray(Primitive(Double))) => prim_type(quote![Double]), + ReturnType::Returns(NonArray(Primitive(Float))) => prim_type(quote![Float]), + ReturnType::Returns(NonArray(Primitive(Int))) => prim_type(quote![Int]), + ReturnType::Returns(NonArray(Primitive(Long))) => prim_type(quote![Long]), + ReturnType::Returns(NonArray(Primitive(Short))) => prim_type(quote![Short]), + ReturnType::Returns(NonArray(Object { .. })) => { + parse_quote![::jni::signature::ReturnType::Object] + } + ReturnType::Returns(Array { .. }) => parse_quote![::jni::signature::ReturnType::Array], + } +} + +/// A postfix call on a `jni::objects::JValueOwned` instance to convert it to the type specified by +/// `ret`. Since we have this information from the type signature we can perform this conversion +/// in the macro. +fn return_value_conversion_from_sig(ret: ReturnType<'_>) -> TokenStream { + use crate::type_parser::{JavaType::*, NonArray::*}; + + match ret { + ReturnType::Void => quote! { .and_then(::jni::objects::JValueOwned::v) }, + ReturnType::Returns(NonArray(Primitive(p))) => { + let prim = prim_to_union_field(p); + quote! { .and_then(::jni::objects::JValueOwned::#prim) } + } + ReturnType::Returns(NonArray(Object { cls })) => { + let mut conversion = quote! { .and_then(::jni::objects::JValueOwned::l) }; + match cls { + "java/lang/String" => { + conversion.append_all(quote! { .map(::jni::objects::JString::from) }); + } + "java/util/List" => { + conversion.append_all(quote! { .map(::jni::objects::JList::from) }); + } + "java/util/Map" => { + conversion.append_all(quote! { .map(::jni::objects::JMap::from) }); + } + _ => { + // Already a JObject, so we are good here + } + } + conversion + } + ReturnType::Returns(Array { + depth, + ty: Primitive(p), + }) if depth.get() == 1 => { + let sys_type = prim_to_sys_type(p); + quote! { + .and_then(::jni::objects::JValueOwned::l) + .map(::jni::objects::JPrimitiveArray::<#sys_type>::from) + } + } + ReturnType::Returns(Array { .. }) => quote! { + .and_then(::jni::objects::JValueOwned::l) + .map(::jni::objects::JObjectArray::from) + }, + } +} + +/// From a [`Primitive`], this gets the `jni::sys::jvalue` union field name for that type. This is +/// also the `jni::objects::JValueGen` getter name. +fn prim_to_union_field(p: Primitive) -> Ident { + quote::format_ident!("{}", p.as_char().to_ascii_lowercase()) +} + +/// From a [`Primitive`], this gets the matching `jvalue::sys` type. +fn prim_to_sys_type(p: Primitive) -> Type { + match p { + Primitive::Boolean => parse_quote![::jni::sys::jboolean], + Primitive::Byte => parse_quote![::jni::sys::jbyte], + Primitive::Char => parse_quote![::jni::sys::jchar], + Primitive::Double => parse_quote![::jni::sys::jdouble], + Primitive::Float => parse_quote![::jni::sys::jfloat], + Primitive::Int => parse_quote![::jni::sys::jint], + Primitive::Long => parse_quote![::jni::sys::jlong], + Primitive::Short => parse_quote![::jni::sys::jshort], + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] +mod tests { + use super::*; + use crate::test_util::contains_ident; + use quote::ToTokens; + use syn::parse_quote; + + fn example_method_call() -> MethodCall { + MethodCall::new( + parse_quote![&mut env], + MethodInfo::new( + parse_quote![&FOO_CLS], + parse_quote!["example"], + parse_quote!["(II)I"], + ), + Receiver::Instance(parse_quote![&foo]), + vec![parse_quote![123], parse_quote![2 + 3]], + ) + } + + #[test] + fn args_are_counted() { + let mut call = example_method_call(); + call.arg_exprs.push(parse_quote![too_many]); + + let CodegenError(_span, kind) = call.generate().unwrap_err(); + + assert_eq!( + ErrorKind::InvalidArgsLength { + expected: 2, + found: 3 + }, + kind + ); + } + + #[test] + fn constructor_return_type_is_void() { + let mut call = example_method_call(); + call.receiver = Receiver::Constructor; + + let CodegenError(_span, kind) = call.generate().unwrap_err(); + + assert_eq!(ErrorKind::ConstructorRetValShouldBeVoid, kind); + } + + #[test] + fn invalid_type_sig_is_error() { + let mut call = example_method_call(); + call.method.sig = parse_quote!["L"]; + call.method.sig_str = call.method.sig.value(); + + let CodegenError(_span, kind) = call.generate().unwrap_err(); + + assert_eq!(ErrorKind::InvalidTypeSignature, kind); + } + + #[test] + fn jni_types_are_used_for_stdlib_classes_input() { + let types = [ + ("Ljava/lang/String;", "JString"), + ("Ljava/util/Map;", "JMap"), + ("Ljava/util/List;", "JList"), + ("[Ljava/lang/String;", "JObjectArray"), + ("[[I", "JObjectArray"), + ("[I", "JPrimitiveArray"), + ("Lcom/example/MyObject;", "JObject"), + ("Z", "jboolean"), + ("C", "jchar"), + ("B", "jbyte"), + ("S", "jshort"), + ("I", "jint"), + ("J", "jlong"), + ("F", "jfloat"), + ("D", "jdouble"), + ]; + + for (desc, jni_type) in types { + let jt = JavaType::try_from_str(desc).unwrap(); + let expr = parse_quote![some_value]; + + let jvalue = generate_jvalue(jt, &expr); + + assert!( + contains_ident(jvalue, jni_type), + "desc: {desc}, jni_type: {jni_type}" + ); + } + } + + #[test] + fn jni_types_are_used_for_stdlib_classes_output() { + let types = [ + ("Ljava/lang/String;", "JString"), + ("Ljava/util/Map;", "JMap"), + ("Ljava/util/List;", "JList"), + ("[Ljava/lang/String;", "JObjectArray"), + ("[[I", "JObjectArray"), + ("[I", "JPrimitiveArray"), + ]; + + for (desc, jni_type) in types { + let rt = ReturnType::try_from_str(desc).unwrap(); + + let conversion = return_value_conversion_from_sig(rt); + + assert!( + contains_ident(conversion, jni_type), + "desc: {desc}, jni_type: {jni_type}" + ); + } + } + + #[test] + fn return_type_passed_to_jni_is_correct() { + let types = [ + ("Ljava/lang/String;", "Object"), + ("Ljava/util/Map;", "Object"), + ("Ljava/util/List;", "Object"), + ("[Ljava/lang/String;", "Array"), + ("[[I", "Array"), + ("[I", "Array"), + ("V", "Void"), + ("Z", "Boolean"), + ("C", "Char"), + ("B", "Byte"), + ("S", "Short"), + ("I", "Int"), + ("J", "Long"), + ("F", "Float"), + ("D", "Double"), + ]; + + for (desc, return_type) in types { + let rt = ReturnType::try_from_str(desc).unwrap(); + + let expr = return_type_from_sig(rt).into_token_stream(); + + assert!( + contains_ident(expr, return_type), + "desc: {desc}, return_type: {return_type}" + ); + } + } + + #[test] + fn method_desc_is_correct() { + let mut call = example_method_call(); + call.method.sig = parse_quote!["(II)V"]; + call.method.sig_str = call.method.sig.value(); + + let tests = [ + (Receiver::Constructor, "constructor"), + (Receiver::Static, "static_method"), + (Receiver::Instance(parse_quote![this_value]), "method"), + ]; + + for (receiver, method_ident) in tests { + let desc = receiver.generate_method_desc(&call.method); + let rhs = desc.expr.into_token_stream(); + + assert!(contains_ident(rhs, method_ident), "method: {method_ident}"); + } + } + + #[test] + fn jni_call_is_correct() { + let mut call = example_method_call(); + call.method.sig = parse_quote!["(II)V"]; + call.method.sig_str = call.method.sig.value(); + let sig = call.method.sig().unwrap(); + let args = parse_quote![test_stub]; + + let tests = [ + (Receiver::Constructor, "new_object_unchecked"), + (Receiver::Static, "call_static_method_unchecked"), + ( + Receiver::Instance(parse_quote![this_value]), + "call_method_unchecked", + ), + ]; + + for (receiver, method_ident) in tests { + let call = receiver + .generate_call(&call.env, &call.method, &sig, &args) + .unwrap(); + + assert!(contains_ident(call, method_ident), "method: {method_ident}"); + } + } +}
diff --git a/nearby/util/pourover_macro_core/src/jni_method.rs b/common/pourover_macro/src/jni_method.rs similarity index 64% rename from nearby/util/pourover_macro_core/src/jni_method.rs rename to common/pourover_macro/src/jni_method.rs index 73ca155..760aa64 100644 --- a/nearby/util/pourover_macro_core/src/jni_method.rs +++ b/common/pourover_macro/src/jni_method.rs
@@ -13,7 +13,6 @@ // limitations under the License. use proc_macro2::TokenStream; -use quote::ToTokens; use syn::{punctuated::Punctuated, spanned::Spanned, ItemFn, LitStr, Token}; mod meta; @@ -23,20 +22,18 @@ use meta::JniMethodMeta; use substitutions::substitute_method_chars; -/// See `pourover_macro::jni_method` for usage. -pub fn jni_method(meta: TokenStream, item: TokenStream) -> TokenStream { - match jni_method_inner(meta, item) { - Ok(out) => out.to_token_stream(), - Err(err) => err.to_compile_error(), - } -} - -fn jni_method_inner(meta: TokenStream, item: TokenStream) -> syn::Result<impl ToTokens> { +pub fn jni_method(meta: TokenStream, item: TokenStream) -> syn::Result<ItemFn> { let meta = syn::parse2::<JniMethodMeta>(meta)?; let mut func = syn::parse2::<ItemFn>(item)?; // Check that ABI is set to `extern "system"` - if let Some(ref abi @ syn::Abi { name: Some(ref abi_name), .. }) = func.sig.abi { + if let Some( + ref abi @ syn::Abi { + name: Some(ref abi_name), + .. + }, + ) = func.sig.abi + { if abi_name.value() != "system" { return Err(syn::Error::new( abi.span(), @@ -52,10 +49,14 @@ let export_attr = { // Format the name of the function as expected by the JNI layer - let method_name = func.sig.ident.to_string(); + let (method_name, method_name_span) = if let Some(meta_name) = &meta.method_name { + (meta_name.value(), meta_name.span()) + } else { + (func.sig.ident.to_string(), func.sig.ident.span()) + }; if method_name.starts_with("Java_") { return Err(syn::Error::new( - func.sig.ident.span(), + method_name_span, "The `jni_method` attribute will perform the JNI name formatting", )); } @@ -64,13 +65,18 @@ // NOTE: doesn't handle overload suffix let link_name = LitStr::new( &format!("Java_{class}_{method_name}", class = &meta.class_desc), - func.sig.ident.span(), + method_name_span, ); syn::parse_quote! { #[export_name = #link_name] } }; - let allow_attr = syn::parse_quote! { #[allow(non_snake_case)] }; - func.attrs.extend([export_attr, allow_attr]); + func.attrs.push(export_attr); + + // Allow function name to be non_snake_case if we are using it as the Java method name + if meta.method_name.is_none() { + let allow_attr = syn::parse_quote! { #[allow(non_snake_case)] }; + func.attrs.push(allow_attr); + } // Add a panic handler if requested if let Some(panic_returns) = meta.panic_returns { @@ -108,50 +114,11 @@ } #[cfg(test)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] mod tests { use super::*; - use proc_macro2::{TokenStream, TokenTree}; - use quote::quote; - - fn contains_ident(stream: TokenStream, ident: &str) -> bool { - /// Iterator that traverses TokenTree:Group structures in preorder. - struct FlatStream { - streams: Vec<<TokenStream as IntoIterator>::IntoIter>, - } - - impl FlatStream { - fn new(stream: TokenStream) -> Self { - Self { streams: vec![stream.into_iter()] } - } - } - - impl Iterator for FlatStream { - type Item = TokenTree; - - fn next(&mut self) -> Option<TokenTree> { - let next = loop { - let stream = self.streams.last_mut()?; - if let Some(next) = stream.next() { - break next; - } - self.streams.pop(); - }; - - if let TokenTree::Group(group) = &next { - self.streams.push(group.stream().into_iter()); - } - - Some(next) - } - } - - FlatStream::new(stream) - .filter_map(|tree| { - let TokenTree::Ident(ident) = tree else { return None }; - Some(ident.to_string()) - }) - .any(|ident_str| ident_str == ident) - } + use crate::test_util::contains_ident; + use quote::{quote, ToTokens}; #[test] fn can_parse() { @@ -170,9 +137,9 @@ } }; - let out = jni_method(meta, func); + let out = jni_method(meta, func).unwrap(); - assert!(contains_ident(out, "catch_unwind")); + assert!(contains_ident(out.into_token_stream(), "catch_unwind")); } fn parse_example_output() -> syn::ItemFn { @@ -191,7 +158,27 @@ } }; - syn::parse2(jni_method(meta, func)).expect("Proc macro output should be a function item") + jni_method(meta, func).expect("failed to generate example") + } + + fn parse_example_output_method_name() -> syn::ItemFn { + let meta = quote! { + package = "com.example", + class = "Foo.Inner", + method_name = "nativeBar", + panic_returns = false, + }; + + let func = quote! { + extern "system" fn native_bar<'local>( + mut env: JNIEnv<'local>, + this: JObject<'local> + ) -> jint { + 123 + } + }; + + jni_method(meta, func).expect("failed to generate example") } #[test] @@ -213,7 +200,10 @@ if !nv.path.is_ident("export_name") { return None; } - let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }) = &nv.value + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &nv.value else { return None; }; @@ -224,6 +214,33 @@ } #[test] + fn check_output_export_name_with_method_name() { + let out = parse_example_output_method_name(); + + let export_name = out + .attrs + .iter() + .find_map(|attr| { + let syn::Meta::NameValue(nv) = &attr.meta else { + return None; + }; + if !nv.path.is_ident("export_name") { + return None; + } + let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &nv.value + else { + return None; + }; + Some(lit_str.value()) + }) + .expect("Failed to find `export_name` attribute"); + assert_eq!("Java_com_example_Foo_00024Inner_nativeBar", export_name); + } + + #[test] fn check_output_allow_non_snake_case() { let out = parse_example_output(); @@ -246,6 +263,25 @@ } #[test] + fn check_output_allow_non_snake_case_not_present_with_method_name() { + let out = parse_example_output_method_name(); + + let allow_attr = out.attrs.iter().find(|attr| { + let syn::Meta::List(ml) = &attr.meta else { + return false; + }; + if !ml.path.is_ident("allow") { + return false; + } + let Ok(value) = syn::parse2::<syn::Path>(ml.tokens.clone()) else { + return false; + }; + value.is_ident("non_snake_case") + }); + assert!(allow_attr.is_none()); + } + + #[test] fn no_panic_returns() { let meta = quote! { package = "com.example", @@ -261,7 +297,10 @@ } }; - let out = jni_method(meta, func); + let out = match jni_method(meta, func) { + Ok(item_fn) => item_fn.into_token_stream(), + Err(err) => err.into_compile_error(), + }; assert!(!contains_ident(out.clone(), "compile_error")); assert!(!contains_ident(out, "catch_unwind")); } @@ -283,7 +322,7 @@ } }; - let Err(err) = jni_method_inner(meta, func) else { + let Err(err) = jni_method(meta, func) else { panic!("Should fail to generate code"); }; @@ -309,7 +348,7 @@ } }; - let Err(err) = jni_method_inner(meta, func) else { + let Err(err) = jni_method(meta, func) else { panic!("Should fail to generate code"); }; @@ -335,7 +374,34 @@ } }; - let Err(err) = jni_method_inner(meta, func) else { + let Err(err) = jni_method(meta, func) else { + panic!("Should fail to generate code"); + }; + + assert!(err + .to_string() + .contains("The `jni_method` attribute will perform the JNI name formatting")); + } + + #[test] + fn already_mangled_method_name() { + let meta = quote! { + package = "com.example", + class = "Foo.Inner", + method_name = "Java_com_example_Foo_00024Inner_nativeFoo", + panic_returns = false, + }; + + let func = quote! { + extern "system" fn native_foo<'local>( + mut env: JNIEnv<'local>, + this: JObject<'local> + ) -> jint { + 123 + } + }; + + let Err(err) = jni_method(meta, func) else { panic!("Should fail to generate code"); };
diff --git a/nearby/util/pourover_macro_core/src/jni_method/meta.rs b/common/pourover_macro/src/jni_method/meta.rs similarity index 70% rename from nearby/util/pourover_macro_core/src/jni_method/meta.rs rename to common/pourover_macro/src/jni_method/meta.rs index 1e07edd..85e8c1a 100644 --- a/nearby/util/pourover_macro_core/src/jni_method/meta.rs +++ b/common/pourover_macro/src/jni_method/meta.rs
@@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use proc_macro2::Span; use syn::{ parse::{Parse, ParseStream}, - Expr, Token, + Expr, LitStr, Token, }; use super::meta_arg::MetaArg; @@ -23,6 +24,8 @@ pub struct JniMethodMeta { /// The class descriptor in [export_name format](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names) pub class_desc: String, + /// The method name in Java. Use the Rust method name if not specified + pub method_name: Option<LitStr>, /// The expression to run when a panic is encountered. The value of this expression will be /// returned by the annotated function. pub panic_returns: Option<Expr>, @@ -32,35 +35,58 @@ fn parse(stream: ParseStream<'_>) -> syn::Result<Self> { let mut package = None; let mut class = None; + let mut method_name = None; let mut panic_returns = None; + fn set_once<T>(opt: &mut Option<T>, value: T, span: Span, field: &str) -> syn::Result<()> { + if let Some(_old) = opt.replace(value) { + return Err(syn::Error::new( + span, + format!("`{field}` should not be specified twice"), + )); + } + Ok(()) + } + type Structure = syn::punctuated::Punctuated<MetaArg, Token![,]>; for arg in Structure::parse_terminated(stream)? { match arg { - MetaArg::Package { package_token, value, .. } => { - if let Some(_old) = package.replace(value) { - return Err(syn::Error::new( - package_token.span, - "`package` should not be specified twice", - )); - } + MetaArg::Package { + package_token, + value, + .. + } => { + set_once(&mut package, value, package_token.span, "package")?; } - MetaArg::Class { class_token, value, .. } => { - if let Some(_old) = class.replace(value) { - return Err(syn::Error::new( - class_token.span, - "`class` should not be specified twice", - )); - } + MetaArg::Class { + class_token, value, .. + } => { + set_once(&mut class, value, class_token.span, "class")?; } - MetaArg::PanicReturns { panic_returns_token, value, .. } => { - if let Some(_old) = panic_returns.replace(value) { - return Err(syn::Error::new( - panic_returns_token.span, - "`panic_returns` should not be specified twice", - )); - } + MetaArg::MethodName { + method_name_token, + value, + .. + } => { + set_once( + &mut method_name, + value, + method_name_token.span, + "method_name", + )?; + } + MetaArg::PanicReturns { + panic_returns_token, + value, + .. + } => { + set_once( + &mut panic_returns, + value, + panic_returns_token.span, + "panic_returns", + )?; } } } @@ -86,7 +112,11 @@ let class = substitute_class_chars(&class.value()); let class_desc = format!("{package}_{class}"); - Ok(Self { class_desc, panic_returns }) + Ok(Self { + class_desc, + method_name, + panic_returns, + }) } }
diff --git a/nearby/util/pourover_macro_core/src/jni_method/meta_arg.rs b/common/pourover_macro/src/jni_method/meta_arg.rs similarity index 73% rename from nearby/util/pourover_macro_core/src/jni_method/meta_arg.rs rename to common/pourover_macro/src/jni_method/meta_arg.rs index aa28aa1..02b1900 100644 --- a/nearby/util/pourover_macro_core/src/jni_method/meta_arg.rs +++ b/common/pourover_macro/src/jni_method/meta_arg.rs
@@ -21,14 +21,32 @@ pub mod kw { syn::custom_keyword!(package); syn::custom_keyword!(class); + syn::custom_keyword!(method_name); syn::custom_keyword!(panic_returns); } /// Arguments to the attribute pub enum MetaArg { - Package { package_token: kw::package, _eq_token: Token![=], value: LitStr }, - Class { class_token: kw::class, _eq_token: Token![=], value: LitStr }, - PanicReturns { panic_returns_token: kw::panic_returns, _eq_token: Token![=], value: Expr }, + Package { + package_token: kw::package, + _eq_token: Token![=], + value: LitStr, + }, + Class { + class_token: kw::class, + _eq_token: Token![=], + value: LitStr, + }, + MethodName { + method_name_token: kw::method_name, + _eq_token: Token![=], + value: LitStr, + }, + PanicReturns { + panic_returns_token: kw::panic_returns, + _eq_token: Token![=], + value: Expr, + }, } impl Parse for MetaArg { @@ -46,6 +64,12 @@ _eq_token: stream.parse()?, value: stream.parse()?, }) + } else if lookahead.peek(kw::method_name) { + Ok(MetaArg::MethodName { + method_name_token: stream.parse::<kw::method_name>()?, + _eq_token: stream.parse()?, + value: stream.parse()?, + }) } else if lookahead.peek(kw::panic_returns) { Ok(MetaArg::PanicReturns { panic_returns_token: stream.parse::<kw::panic_returns>()?, @@ -59,6 +83,7 @@ } #[cfg(test)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] mod tests { use super::*; use syn::parse_quote; @@ -87,6 +112,8 @@ panic!("failed to parse") }; - let syn::Expr::Block(_) = value else { panic!("not a block expression") }; + let syn::Expr::Block(_) = value else { + panic!("not a block expression") + }; } }
diff --git a/nearby/util/pourover_macro_core/src/jni_method/substitutions.rs b/common/pourover_macro/src/jni_method/substitutions.rs similarity index 100% rename from nearby/util/pourover_macro_core/src/jni_method/substitutions.rs rename to common/pourover_macro/src/jni_method/substitutions.rs
diff --git a/common/pourover_macro/src/lib.rs b/common/pourover_macro/src/lib.rs new file mode 100644 index 0000000..f46b7b1 --- /dev/null +++ b/common/pourover_macro/src/lib.rs
@@ -0,0 +1,286 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Proc macros for `pourover`. These macros are reexported by the `pourover` crate, so this crate +//! is an implementation detail. + +use proc_macro::TokenStream; + +mod call_method; +mod jni_method; +mod type_parser; + +/// Export a function as a JNI native method. This will attach a `#[export_name = "..."]` attribute that +/// is formatted with the given parameters. The provided `package`, `class`, and `method_name` will +/// be combined and formatted in according to the [JNI method name resolution rules][JNI naming]. +/// +/// [JNI naming]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names +/// +/// # Parameters +/// - `package` (LitStr): the Java package for the class being implemented +/// - `class` (LitStr): the Java class being implemented. Use `Foo.Inner` syntax for inner +/// classes. +/// - `method_name` (*optional* LitStr): the method's name in Java. The Rust function name will be +/// used if this parameter is not set. +/// - `panic_returns` (*optional* Expr): the value to return when a panic is encountered. This can +/// not access local variables. This may only be used with `panic=unwind` and will produce a +/// compile error otherwise. +/// +/// When using `panic_returns` function arguments must be [`std::panic::UnwindSafe`]. See +/// [`std::panic::catch_unwind`] for details. In practice this will not cause issues as JNI +/// arguments and return values are passed by pointer or value and not by Rust reference. +/// +/// # Example +/// ``` +/// # use pourover_macro::jni_method; +/// # use jni::{sys::jint, objects::{JObject, JString}, JNIEnv}; +/// +/// #[jni_method(package = "my.package", class = "Foo", panic_returns = -1)] +/// extern "system" fn getFoo<'local>( +/// mut env: JNIEnv<'local>, +/// this: JObject<'local>, +/// ) -> jint { +/// // ... +/// 0 +/// } +/// ``` +/// +/// This function will be exported with `#[export_name = "Java_my_package_Foo_getFoo"]`. +#[proc_macro_attribute] +pub fn jni_method(meta: TokenStream, item: TokenStream) -> TokenStream { + use quote::ToTokens; + match jni_method::jni_method(meta.into(), item.into()) { + Ok(item_fn) => item_fn.into_token_stream(), + Err(err) => err.into_compile_error(), + } + .into() +} + +/// Call a Java method. +/// +/// # Parameters +/// `call_method!($env, $cls, $name, $sig, $this, $($args),*)` +/// - `env` (Expr: `&mut jni::JNIEnv`): The JNI environment. +/// - `cls` (Expr: `&'static ClassDesc`): The class containing the method. +/// - `name` (Expr: `&'static str`): The name of the method. +/// - `sig` (LitStr): The JNI type signature of the method. This needs to be a literal so that it +/// can be parsed by the macro to type-check args and return a correctly-typed value. +/// - `this` (Expr: `&JObject`): The Java object receiving the method call. +/// - `args` (Expr ...): A variable number of arguments to be passed to the method. +/// +/// # Caching +/// Each macro callsite will generate a `static` `MethodDesc` to cache the +/// method id. Due to this, **this macro call should be wrapped in function** instead of being called +/// multiple times. +/// +/// # Type-Safety +/// The given type signature will be parsed and arguments will be type checked against it. The +/// expected types are from the `jni` crate: +/// - Primitives: `jni::sys::{jboolean, jbyte, jchar, jshort, jint, jlong, jfloat, jdouble}` +/// - Arrays: `jni::objects::{JPrimitiveArray, JObjectArray}` +/// - Objects: `jni::objects::{JObject, JString, JMap, JList}` +/// +/// Similarly, the return type will be one of the types above. +/// +/// # Returns +/// The macro will evaluate to `jni::errors::Result<R>` where `R` is the return type parsed from +/// the type signature. +/// +/// # Example +/// Let's call `sayHello` from the following class. +/// ```java +/// package com.example; +/// class Foo { +/// int sayHello(String name) { /* ... */ } +/// } +/// ``` +/// We can use `call_method!` to implement the function call. +/// ```rust +/// # use jni::{sys::jint, objects::{JObject, JString}, JNIEnv}; +/// # use pourover_macro::call_method; +/// # use pourover::desc::*; +/// static MY_CLASS: ClassDesc = ClassDesc::new("com/example/Foo"); +/// fn say_hello<'l>( +/// env: &mut JNIEnv<'l>, +/// my_obj: &JObject<'_>, +/// name: &JString<'_> +/// ) -> jni::errors::Result<jint> { +/// call_method!(env, &MY_CLASS, "sayHello", "(Ljava/lang/String;)I", my_obj, name) +/// } +/// ``` +#[proc_macro] +pub fn call_method(args: TokenStream) -> TokenStream { + call_method::call_method(args.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +/// Call a static Java method. +/// +/// # Parameters +/// `call_static_method!($env, $cls, $name, $sig, $($args),*)` +/// - `env` (Expr: `&mut jni::JNIEnv`): The JNI environment. +/// - `cls` (Expr: `&'static ClassDesc`): The class containing the method. +/// - `name` (Expr: `&'static str`): The name of the method. +/// - `sig` (LitStr): The JNI type signature of the method. This needs to be a literal so that it +/// can be parsed by the macro to type-check args and return a correctly-typed value. +/// - `args` (Expr ...): A variable number of arguments to be passed to the method. +/// +/// # Caching +/// Each macro callsite will generate a `static` `StaticMethodDesc` to cache the +/// method id. Due to this, **this macro call should be wrapped in function** instead of being called +/// multiple times. +/// +/// # Type-Safety +/// The given type signature will be parsed and arguments will be type checked against it. The +/// expected types are from the `jni` crate: +/// - Primitives: `jni::sys::{jboolean, jbyte, jchar, jshort, jint, jlong, jfloat, jdouble}` +/// - Arrays: `jni::objects::{JPrimitiveArray, JObjectArray}` +/// - Objects: `jni::objects::{JObject, JString, JMap, JList}` +/// +/// Similarly, the return type will be one of the types above. +/// +/// # Returns +/// The macro will evaluate to `jni::errors::Result<R>` where `R` is the return type parsed from +/// the type signature. +/// +/// # Example +/// Let's call `sayHello` from the following class. +/// ```java +/// package com.example; +/// class Foo { +/// static int sayHello(String name) { /* ... */ } +/// } +/// ``` +/// We can use `call_static_method!` to implement the function call. +/// ```rust +/// # use jni::{sys::jint, objects::{JObject, JString}, JNIEnv}; +/// # use pourover_macro::call_static_method; +/// # use pourover::desc::*; +/// static MY_CLASS: ClassDesc = ClassDesc::new("com/example/Foo"); +/// fn say_hello<'l>( +/// env: &mut JNIEnv<'l>, +/// name: &JString<'_> +/// ) -> jni::errors::Result<jint> { +/// call_static_method!(env, &MY_CLASS, "sayHello", "(Ljava/lang/String;)I", name) +/// } +/// ``` +#[proc_macro] +pub fn call_static_method(args: TokenStream) -> TokenStream { + call_method::call_static_method(args.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +/// Call a Java constructor. +/// +/// # Parameters +/// `call_constructor!($env, $cls, $sig, $($args),*)` +/// - `env` (Expr: `&mut jni::JNIEnv`): The JNI environment. +/// - `cls` (Expr: `&'static ClassDesc`): The class to be constructed. +/// - `sig` (LitStr): The JNI type signature of the constructor. This needs to be a literal so that it +/// can be parsed by the macro to type-check args and return a correctly-typed value. +/// - `args` (Expr ...): A variable number of arguments to be passed to the constructor. +/// +/// # Caching +/// Each macro callsite will generate a `static` `MethodDesc` to cache the +/// method id. Due to this, **this macro call should be wrapped in function** instead of being called +/// multiple times. +/// +/// # Type-Safety +/// The given type signature will be parsed and arguments will be type checked against it. The +/// expected types are from the `jni` crate: +/// - Primitives: `jni::sys::{jboolean, jbyte, jchar, jshort, jint, jlong, jfloat, jdouble}` +/// - Arrays: `jni::objects::{JPrimitiveArray, JObjectArray}` +/// - Objects: `jni::objects::{JObject, JString, JMap, JList}` +/// +/// # Returns +/// The macro will evaluate to `jni::errors::Result<jni::objects::JObject>`. +/// +/// # Example +/// Let's call the constructor from the following class. +/// ```java +/// package com.example; +/// class Foo { +/// Foo(String name) { /* ... */ } +/// } +/// ``` +/// We can use `call_constructor!` to implement the function call. +/// ```rust +/// # use jni::{objects::{JObject, JString}, JNIEnv}; +/// # use pourover_macro::call_constructor; +/// # use pourover::desc::*; +/// static MY_CLASS: ClassDesc = ClassDesc::new("com/example/Foo"); +/// fn construct_foo<'l>( +/// env: &mut JNIEnv<'l>, +/// name: &JString<'_> +/// ) -> jni::errors::Result<JObject<'l>> { +/// call_constructor!(env, &MY_CLASS, "(Ljava/lang/String;)V", name) +/// } +/// ``` +#[proc_macro] +pub fn call_constructor(args: TokenStream) -> TokenStream { + call_method::call_constructor(args.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[cfg(test)] +pub(crate) mod test_util { + use proc_macro2::{TokenStream, TokenTree}; + + /// Iterator that traverses TokenTree:Group structures in preorder. + struct FlatStream { + streams: Vec<<TokenStream as IntoIterator>::IntoIter>, + } + + impl FlatStream { + fn new(stream: TokenStream) -> Self { + Self { + streams: vec![stream.into_iter()], + } + } + } + + impl Iterator for FlatStream { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + let next = loop { + let stream = self.streams.last_mut()?; + if let Some(next) = stream.next() { + break next; + } + let _ = self.streams.pop(); + }; + + if let TokenTree::Group(group) = &next { + self.streams.push(group.stream().into_iter()); + } + + Some(next) + } + } + + pub fn contains_ident(stream: TokenStream, ident: &str) -> bool { + FlatStream::new(stream) + .filter_map(|tree| { + let TokenTree::Ident(ident) = tree else { + return None; + }; + Some(ident.to_string()) + }) + .any(|ident_str| ident_str == ident) + } +}
diff --git a/common/pourover_macro/src/type_parser.rs b/common/pourover_macro/src/type_parser.rs new file mode 100644 index 0000000..e6834e2 --- /dev/null +++ b/common/pourover_macro/src/type_parser.rs
@@ -0,0 +1,503 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Parsers for JNI type descriptors. + +// There is code that is used in tests but not in the crate. +#![allow(dead_code)] + +use core::fmt; +use core::num::NonZeroU8; +use nom::{IResult, Parser}; + +/// Describes a type in Java +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum JavaType<'a> { + /// An array type. + Array { + /// The number of dimensions. The JVM spec limits this to 255. + depth: NonZeroU8, + /// The type of objects in the array. + ty: NonArray<'a>, + }, + /// A non-array type. See [`NonArray`]. + NonArray(NonArray<'a>), +} + +impl<'a> JavaType<'a> { + /// Check if this type is a primitive type. + pub fn is_primitive(&self) -> bool { + matches!(*self, Self::NonArray(NonArray::Primitive(_))) + } + + fn parse(s: &'a str) -> IResult<&'a str, JavaType<'a>> { + use nom::bytes::complete::take_while1; + use nom::combinator::{map, map_opt, opt}; + + let parse_array = opt(map_opt(take_while1(|c| c == '['), |brackets: &str| { + u8::try_from(brackets.len()).ok().and_then(NonZeroU8::new) + })); + + map( + parse_array.and(NonArray::parse), + |(depth, ty)| match depth { + Some(depth) => JavaType::Array { depth, ty }, + None => JavaType::NonArray(ty), + }, + )(s) + } + + /// Try to parse a type from the given string in JNI descriptor format. + pub fn try_from_str(s: &'a str) -> Option<Self> { + run_parser(Self::parse, s) + } +} + +impl<'a> fmt::Display for JavaType<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + JavaType::Array { depth, ty } => { + for _ in 0..depth.get() { + write!(f, "[")?; + } + write!(f, "{ty}") + } + JavaType::NonArray(ty) => write!(f, "{ty}"), + } + } +} + +impl<'a> From<NonArray<'a>> for JavaType<'a> { + fn from(ty: NonArray<'a>) -> Self { + JavaType::NonArray(ty) + } +} + +impl<'a> From<Primitive> for JavaType<'a> { + fn from(prim: Primitive) -> Self { + JavaType::NonArray(NonArray::Primitive(prim)) + } +} + +#[cfg(jni)] +impl<'a> From<JavaType<'a>> for jni::signature::ReturnType { + fn from(ty: JavaType<'a>) -> Self { + match ty { + JavaType::Array { .. } => Self::Array, + JavaType::NonArray(NonArray::Object { .. }) => Self::Object, + JavaType::NonArray(NonArray::Primitive(p)) => Self::Primitive(p.into()), + } + } +} + +/// Describes a non-array type in Java +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NonArray<'a> { + /// A primitive type. See [`Primitive`]. + Primitive(Primitive), + /// An object type. + Object { + /// The class name in JNI form. + cls: &'a str, + }, +} + +impl<'a> NonArray<'a> { + fn parse(s: &'a str) -> IResult<&'a str, NonArray<'a>> { + use nom::branch::alt; + use nom::bytes::complete::take_while1; + use nom::character::complete::char; + use nom::combinator::map; + use nom::sequence::delimited; + + let parse_prim = map(Primitive::parse, NonArray::Primitive); + + let parse_object = map( + delimited(char('L'), take_while1(|c| c != ';'), char(';')), + |cls| NonArray::Object { cls }, + ); + + alt((parse_prim, parse_object))(s) + } +} + +impl<'a> fmt::Display for NonArray<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + NonArray::Primitive(p) => write!(f, "{p}"), + NonArray::Object { cls } => write!(f, "L{cls};"), + } + } +} + +impl<'a> From<Primitive> for NonArray<'a> { + fn from(p: Primitive) -> Self { + Self::Primitive(p) + } +} + +/// Describes a primitive type in Java +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Primitive { + /// Java `boolean` + Boolean, + /// Java `byte` + Byte, + /// Java `char` + Char, + /// Java `double` + Double, + /// Java `float` + Float, + /// Java `int` + Int, + /// Java `long` + Long, + /// Java `short` + Short, +} + +impl Primitive { + fn parse(s: &str) -> IResult<&str, Primitive> { + use nom::branch::alt; + use nom::character::complete::char as match_char; + use nom::combinator::value; + + let parse_prim = |c: char, p: Primitive| value(p, match_char(c)); + + alt(( + parse_prim('Z', Primitive::Boolean), + parse_prim('B', Primitive::Byte), + parse_prim('C', Primitive::Char), + parse_prim('D', Primitive::Double), + parse_prim('F', Primitive::Float), + parse_prim('I', Primitive::Int), + parse_prim('J', Primitive::Long), + parse_prim('S', Primitive::Short), + ))(s) + } + + pub fn as_char(&self) -> char { + match self { + Primitive::Boolean => 'Z', + Primitive::Byte => 'B', + Primitive::Char => 'C', + Primitive::Double => 'D', + Primitive::Float => 'F', + Primitive::Int => 'I', + Primitive::Long => 'J', + Primitive::Short => 'S', + } + } +} + +impl fmt::Display for Primitive { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match *self { + Primitive::Boolean => 'Z', + Primitive::Byte => 'B', + Primitive::Char => 'C', + Primitive::Double => 'D', + Primitive::Float => 'F', + Primitive::Int => 'I', + Primitive::Long => 'J', + Primitive::Short => 'S', + } + ) + } +} + +#[cfg(jni)] +impl From<Primitive> for jni::signature::Primitive { + fn from(p: Primitive) -> Self { + match p { + Primitive::Boolean => Self::Boolean, + Primitive::Byte => Self::Byte, + Primitive::Char => Self::Char, + Primitive::Double => Self::Double, + Primitive::Float => Self::Float, + Primitive::Int => Self::Int, + Primitive::Long => Self::Long, + Primitive::Short => Self::Short, + } + } +} + +/// A Java return type. This may be `void`. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ReturnType<'a> { + /// Java `void`. Only valid in return position. + Void, + /// A non-void return type. + Returns(JavaType<'a>), +} + +impl<'a> ReturnType<'a> { + fn parse(s: &'a str) -> IResult<&'a str, ReturnType<'a>> { + use nom::branch::alt; + use nom::character::complete::char; + use nom::combinator::{map, value}; + + alt(( + value(ReturnType::Void, char('V')), + map(JavaType::parse, ReturnType::Returns), + ))(s) + } + + /// Try to parse a return type from the given string in JNI descriptor format. + pub fn try_from_str(s: &'a str) -> Option<Self> { + run_parser(Self::parse, s) + } + + /// Check if the return type is `ReturnType::Void` + pub fn is_void(&self) -> bool { + matches!(*self, Self::Void) + } +} + +impl<'a> From<JavaType<'a>> for ReturnType<'a> { + fn from(ty: JavaType<'a>) -> Self { + Self::Returns(ty) + } +} + +#[cfg(jni)] +impl<'a> From<ReturnType<'a>> for jni::signature::ReturnType { + fn from(ty: ReturnType<'a>) -> Self { + match ty { + ReturnType::Void => Self::Primitive(jni::signature::Primitive::Void), + ReturnType::Returns(ty) => ty.into(), + } + } +} + +/// A type signature of a Java method. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MethodSig<'a> { + /// The types of each argument. + pub args: Vec<JavaType<'a>>, + /// The return type. + pub ret: ReturnType<'a>, +} + +impl<'a> MethodSig<'a> { + fn parse(s: &'a str) -> IResult<&'a str, MethodSig<'a>> { + use nom::character::complete::char; + use nom::combinator::map; + use nom::multi::many0; + use nom::sequence::delimited; + + let parse_args = delimited(char('('), many0(JavaType::parse), char(')')); + let mut parser = map(parse_args.and(ReturnType::parse), |(args, ret)| MethodSig { + args, + ret, + }); + + parser(s) + } + + /// Try to parse a method signature from the given string in JNI descriptor format. + pub fn try_from_str(s: &'a str) -> Option<Self> { + run_parser(Self::parse, s) + } +} + +/// Helper to run a parser and return its result if it parsed the entire string. +fn run_parser<'a, O, E>(mut parser: impl Parser<&'a str, O, E>, s: &'a str) -> Option<O> { + parser.parse(s).ok().and_then(|(rest, out)| { + if !rest.is_empty() { + return None; + } + Some(out) + }) +} + +#[cfg(test)] +#[allow(clippy::unwrap_used, clippy::indexing_slicing)] +mod test { + use super::*; + + #[test] + fn parse_primitive() { + let (rest, parsed) = JavaType::parse("II").unwrap(); + assert_eq!("I", rest); + assert_eq!( + JavaType::NonArray(NonArray::Primitive(Primitive::Int)), + parsed + ); + } + + #[test] + fn parse_object() { + let (rest, parsed) = JavaType::parse("Ljava/lang/String;I").unwrap(); + assert_eq!("I", rest); + assert_eq!( + JavaType::NonArray(NonArray::Object { + cls: "java/lang/String" + }), + parsed + ); + } + + #[test] + fn parse_primitive_array() { + let (rest, parsed) = JavaType::parse("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[II").unwrap(); + assert_eq!("I", rest); + assert_eq!( + JavaType::Array { + depth: NonZeroU8::new(255).unwrap(), + ty: NonArray::Primitive(Primitive::Int) + }, + parsed + ); + } + + #[test] + fn parse_object_array() { + let (rest, parsed) = JavaType::parse("[[[Ljava/lang/String;I").unwrap(); + assert_eq!("I", rest); + assert_eq!( + JavaType::Array { + depth: NonZeroU8::new(3).unwrap(), + ty: NonArray::Object { + cls: "java/lang/String" + } + }, + parsed + ); + } + + #[test] + fn parse_invalid_array() { + let opt = JavaType::try_from_str("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[I"); + + assert_eq!(None, opt); + } + + #[test] + fn parse_invalid_method() { + let parsed = MethodSig::try_from_str("I(I)I"); + assert_eq!(None, parsed); + } + + #[test] + fn parse_argless_method() { + let parsed = MethodSig::try_from_str("()V").unwrap(); + assert_eq!(ReturnType::Void, parsed.ret); + assert_eq!(0, parsed.args.len()); + } + + #[test] + fn parse_void_method() { + let parsed = MethodSig::try_from_str("([ILjava/lang/String;Z)V").unwrap(); + assert_eq!(ReturnType::Void, parsed.ret); + assert_eq!(3, parsed.args.len()); + assert_eq!( + JavaType::Array { + depth: NonZeroU8::new(1).unwrap(), + ty: NonArray::Primitive(Primitive::Int) + }, + parsed.args[0] + ); + assert_eq!( + JavaType::NonArray(NonArray::Object { + cls: "java/lang/String" + }), + parsed.args[1] + ); + assert_eq!( + JavaType::NonArray(NonArray::Primitive(Primitive::Boolean)), + parsed.args[2] + ); + } + + #[test] + fn parse_nonvoid_method() { + let parsed = MethodSig::try_from_str("([ILjava/lang/String;Z)D").unwrap(); + assert_eq!( + ReturnType::Returns(JavaType::NonArray(NonArray::Primitive(Primitive::Double))), + parsed.ret + ); + assert_eq!(3, parsed.args.len()); + assert_eq!( + JavaType::Array { + depth: NonZeroU8::new(1).unwrap(), + ty: NonArray::Primitive(Primitive::Int) + }, + parsed.args[0] + ); + assert_eq!( + JavaType::NonArray(NonArray::Object { + cls: "java/lang/String" + }), + parsed.args[1] + ); + assert_eq!( + JavaType::NonArray(NonArray::Primitive(Primitive::Boolean)), + parsed.args[2] + ); + } + + #[test] + fn parse_trailing_data_will_error() { + assert!(JavaType::try_from_str("Itrailing").is_none()); + assert!(JavaType::try_from_str("Lcom/example/Foo;trailing").is_none()); + assert!(JavaType::try_from_str("[Ztrailing").is_none()); + assert!(MethodSig::try_from_str("()Itrailing").is_none()); + assert!(MethodSig::try_from_str("()Lcom/example/Foo;trailing").is_none()); + assert!(MethodSig::try_from_str("()[Ztrailing").is_none()); + } + + #[test] + fn java_type_roundtrip_through_display() { + let tests = [ + "Z", + "C", + "B", + "S", + "I", + "J", + "F", + "D", + "Ljava/lang/String;", + "[Z", + "[[B", + "[[[Ljava/lang/String;", + ]; + + for test in tests { + let parsed = JavaType::try_from_str(test).unwrap(); + + let display = format!("{parsed}"); + + assert_eq!(test, display); + } + } + + #[test] + fn test_is_prim() { + assert!(JavaType::try_from_str("I").unwrap().is_primitive()); + assert!(JavaType::try_from_str("Z").unwrap().is_primitive()); + assert!(!JavaType::try_from_str("[I").unwrap().is_primitive()); + assert!(!JavaType::try_from_str("[Ljava/lang/String;") + .unwrap() + .is_primitive()); + assert!(!JavaType::try_from_str("Ljava/lang/String;") + .unwrap() + .is_primitive()); + } +}
diff --git a/nearby/Cargo.lock b/nearby/Cargo.lock index e50e7b7..da61780 100644 --- a/nearby/Cargo.lock +++ b/nearby/Cargo.lock
@@ -61,9 +61,9 @@ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -144,6 +144,15 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] name = "array_ref" version = "0.1.0" @@ -238,9 +247,9 @@ [[package]] name = "bstr" -version = "1.6.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "serde", @@ -252,10 +261,10 @@ dependencies = [ "anyhow", "chrono", - "clap 4.5.1", - "cmd-runner", + "clap 4.5.4", + "cmd_runner", "crossbeam", - "env_logger", + "env_logger 0.10.2", "file-header", "glob", "globset", @@ -268,7 +277,7 @@ "tempfile", "thiserror", "walkdir", - "which", + "xshell", ] [[package]] @@ -311,7 +320,7 @@ checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49" dependencies = [ "clap 3.2.25", - "heck", + "heck 0.4.1", "indexmap", "log", "proc-macro2", @@ -328,6 +337,9 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cesu8" @@ -343,13 +355,15 @@ [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", "windows-targets 0.52.3", ] @@ -407,9 +421,9 @@ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -417,9 +431,9 @@ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -429,11 +443,11 @@ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.50", @@ -455,12 +469,18 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] -name = "cmd-runner" +name = "cmd_runner" version = "0.1.0" dependencies = [ "anyhow", + "chrono", + "clap 4.5.4", + "file-header", + "globset", + "log", "owo-colors", "shell-escape", + "xshell", ] [[package]] @@ -518,10 +538,10 @@ "anes", "cast", "ciborium", - "clap 4.5.1", + "clap 4.5.4", "criterion-plot", "is-terminal", - "itertools", + "itertools 0.10.5", "num-traits", "once_cell", "oorandom", @@ -542,7 +562,7 @@ checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -619,7 +639,7 @@ checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -631,7 +651,7 @@ checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "typenum", ] @@ -686,7 +706,7 @@ "p256", "rand", "rand_chacha", - "rand_core 0.6.4", + "rand_core", "sec1", "sha2", "subtle", @@ -716,6 +736,16 @@ ] [[package]] +name = "crypto_provider_test-fuzz" +version = "0.0.0" +dependencies = [ + "crypto_provider", + "crypto_provider_default", + "derive_fuzztest", + "libfuzzer-sys", +] + +[[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -763,6 +793,35 @@ ] [[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "derive_fuzztest" +version = "0.1.0" +dependencies = [ + "arbitrary", + "derive_fuzztest_macro", + "quickcheck", +] + +[[package]] +name = "derive_fuzztest_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -797,7 +856,7 @@ dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", + "rand_core", "serde", "sha2", "subtle", @@ -823,7 +882,7 @@ "generic-array", "group", "hkdf", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -831,6 +890,16 @@ [[package]] name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" @@ -864,7 +933,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -898,12 +967,6 @@ ] [[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -943,15 +1006,15 @@ [[package]] name = "globset" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aca8bbd8e0707c1887a8bbb7e6b40e228f251ff5d62c8220a4a7a53c73aff006" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata", + "regex-syntax", ] [[package]] @@ -961,7 +1024,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -975,8 +1038,6 @@ name = "handle_map" version = "0.1.0" dependencies = [ - "criterion", - "lazy_static", "lock_adapter", ] @@ -1007,6 +1068,12 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1121,22 +1188,21 @@ ] [[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] -name = "java-locator" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90003f2fd9c52f212c21d8520f1128da0080bad6fff16b68fe6e7f2f0c3780c2" -dependencies = [ - "glob", - "lazy_static", -] - -[[package]] name = "jni" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1145,9 +1211,7 @@ "cesu8", "cfg-if", "combine", - "java-locator", "jni-sys", - "libloading", "log", "thiserror", "walkdir", @@ -1161,6 +1225,15 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] +name = "jobserver" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2" +dependencies = [ + "libc", +] + +[[package]] name = "js-sys" version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1186,7 +1259,7 @@ "anyhow", "base64", "blake2", - "clap 4.5.1", + "clap 4.5.4", "criterion", "crypto_provider", "crypto_provider_default", @@ -1206,6 +1279,32 @@ ] [[package]] +name = "ldt-fuzz" +version = "0.1.0" +dependencies = [ + "arbitrary", + "crypto_provider_rustcrypto", + "derive_fuzztest", + "ldt", + "libfuzzer-sys", + "xts_aes", +] + +[[package]] +name = "ldt-np-adv-fuzz" +version = "0.1.0" +dependencies = [ + "arbitrary", + "crypto_provider_rustcrypto", + "derive_fuzztest", + "ldt", + "ldt_np_adv", + "libfuzzer-sys", + "np_hkdf", + "xts_aes", +] + +[[package]] name = "ldt_np_adv" version = "0.1.0" dependencies = [ @@ -1225,6 +1324,7 @@ "rand_pcg", "serde_json", "test_helper", + "test_vector_hkdf", "xts_aes", ] @@ -1270,13 +1370,14 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "libloading" -version = "0.7.4" +name = "libfuzzer-sys" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" dependencies = [ - "cfg-if", - "winapi", + "arbitrary", + "cc", + "once_cell", ] [[package]] @@ -1315,15 +1416,15 @@ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memoffset" @@ -1383,6 +1484,7 @@ "strum", "strum_macros", "test_helper", + "test_vector_hkdf", "tinyvec", "xts_aes", ] @@ -1394,6 +1496,7 @@ "array_view", "crypto_provider", "np_adv", + "np_hkdf", "sink", ] @@ -1430,6 +1533,8 @@ "np_adv", "np_adv_dynamic", "np_hkdf", + "strum", + "strum_macros", ] [[package]] @@ -1446,10 +1551,24 @@ "rand_ext", "serde_json", "test_helper", + "test_vector_hkdf", "xts_aes", ] [[package]] +name = "np_java_ffi" +version = "0.1.0" +dependencies = [ + "crypto_provider_default", + "handle_map", + "jni", + "np_adv", + "np_ffi_core", + "pourover", + "pourover_macro", +] + +[[package]] name = "num-bigint" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1597,13 +1716,7 @@ name = "pourover_macro" version = "0.1.0" dependencies = [ - "pourover_macro_core", -] - -[[package]] -name = "pourover_macro_core" -version = "0.1.0" -dependencies = [ + "nom", "proc-macro2", "quote", "syn 2.0.50", @@ -1685,6 +1798,17 @@ ] [[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger 0.8.4", + "log", + "rand", +] + +[[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1701,7 +1825,7 @@ dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1711,17 +1835,11 @@ checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] [[package]] name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - -[[package]] -name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" @@ -1730,14 +1848,6 @@ ] [[package]] -name = "rand_core_05_adapter" -version = "0.1.0" -dependencies = [ - "rand", - "rand_core 0.5.1", -] - -[[package]] name = "rand_ext" version = "0.1.0" dependencies = [ @@ -1753,7 +1863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2039,7 +2149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -2100,10 +2210,19 @@ version = "0.1.0" dependencies = [ "hex", + "itertools 0.12.1", "serde_json", ] [[package]] +name = "test_vector_hkdf" +version = "0.1.0" +dependencies = [ + "crypto_provider", + "crypto_provider_default", +] + +[[package]] name = "textwrap" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2172,7 +2291,6 @@ "rand", "rand_chacha", "ukey2_connections", - "ukey2_rs", ] [[package]] @@ -2191,6 +2309,19 @@ ] [[package]] +name = "ukey2_connections-fuzz" +version = "0.1.0" +dependencies = [ + "arbitrary", + "crypto_provider_rustcrypto", + "derive_fuzztest", + "libfuzzer-sys", + "rand_chacha", + "ukey2_connections", + "ukey2_rs", +] + +[[package]] name = "ukey2_jni" version = "0.1.0" dependencies = [ @@ -2203,7 +2334,6 @@ "rand", "rand_chacha", "ukey2_connections", - "ukey2_rs", ] [[package]] @@ -2232,10 +2362,9 @@ name = "ukey2_shell" version = "0.1.0" dependencies = [ - "clap 4.5.1", + "clap 4.5.4", "crypto_provider_rustcrypto", "ukey2_connections", - "ukey2_rs", ] [[package]] @@ -2620,7 +2749,35 @@ checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", +] + +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" + +[[package]] +name = "xts-aes-fuzz" +version = "0.0.0" +dependencies = [ + "arbitrary", + "crypto_provider", + "crypto_provider_rustcrypto", + "derive_fuzztest", + "ldt_tbc", + "libfuzzer-sys", + "xts_aes", ] [[package]]
diff --git a/nearby/Cargo.toml b/nearby/Cargo.toml index 4897eaa..f69bcf7 100644 --- a/nearby/Cargo.toml +++ b/nearby/Cargo.toml
@@ -2,6 +2,7 @@ members = [ "connections/ukey2/ukey2", "connections/ukey2/ukey2_connections", + "connections/ukey2/ukey2_connections/fuzz", "connections/ukey2/ukey2_c_ffi", "connections/ukey2/ukey2_jni", "connections/ukey2/ukey2_proto", @@ -10,11 +11,13 @@ "crypto/crypto_provider_rustcrypto", "crypto/crypto_provider_stubs", "crypto/crypto_provider_test", + "crypto/crypto_provider_test/fuzz", "crypto/crypto_provider_default", - "crypto/rand_core_05_adapter", "presence/array_view", "presence/ldt", + "presence/ldt/fuzz", "presence/ldt_np_adv", + "presence/ldt_np_adv/fuzz", "presence/ldt_np_adv_ffi", "presence/ldt_np_jni", "presence/ldt_tbc", @@ -24,15 +27,13 @@ "presence/np_ed25519", "presence/np_ffi_core", "presence/np_hkdf", + "presence/np_java_ffi", "presence/rand_ext", "presence/sink", "presence/test_helper", + "presence/test_vector_hkdf", "presence/xts_aes", - "util/lock_adapter", - "util/handle_map", - "util/pourover", - "util/pourover_macro", - "util/pourover_macro_core", + "presence/xts_aes/fuzz", ] # TODO: remove boringssl once we figure out a better plan for integrating the build system @@ -41,35 +42,35 @@ ] [workspace.lints.rust] -unsafe_code = "deny" missing_docs = "deny" trivial_casts = "deny" trivial_numeric_casts = "deny" +unsafe_code = "deny" +unsafe_op_in_unsafe_fn = "deny" unused_extern_crates = "deny" unused_import_braces = "deny" unused_results = "deny" [workspace.lints.clippy] -indexing_slicing = "deny" -unwrap_used = "deny" -panic = "deny" expect_used = "deny" +indexing_slicing = "deny" +panic = "deny" +unwrap_used = "deny" [workspace.dependencies] # local crates array_ref = { path = "presence/array_ref" } array_view = { path = "presence/array_view" } crypto_provider = { path = "crypto/crypto_provider", default-features = false } -crypto_provider_default = { path = "crypto/crypto_provider_default", default-features=false} +crypto_provider_default = { path = "crypto/crypto_provider_default", default-features = false } crypto_provider_boringssl = { path = "crypto/crypto_provider_boringssl" } crypto_provider_rustcrypto = { path = "crypto/crypto_provider_rustcrypto" } crypto_provider_stubs = { path = "crypto/crypto_provider_stubs" } crypto_provider_test = { path = "crypto/crypto_provider_test" } -lock_adapter = { path = "util/lock_adapter" } -handle_map = { path = "util/handle_map" } -rand_core_05_adapter = { path = "crypto/rand_core_05_adapter" } rand_ext = { path = "presence/rand_ext" } test_helper = { path = "presence/test_helper" } +ukey2_connections = { path = "connections/ukey2/ukey2_connections" } +ukey2_rs = { path = "connections/ukey2/ukey2" } ukey2_proto = { path = "connections/ukey2/ukey2_proto" } np_hkdf = { path = "presence/np_hkdf" } xts_aes = { path = "presence/xts_aes" } @@ -80,10 +81,17 @@ np_adv_dynamic = { path = "presence/np_adv_dynamic" } np_ed25519 = { path = "presence/np_ed25519" } np_ffi_core = { path = "presence/np_ffi_core", default-features=false } -pourover = { path = "util/pourover" } -pourover_macro = { path = "util/pourover_macro" } -pourover_macro_core = { path = "util/pourover_macro_core" } +np_java_ffi = { path = "presence/np_java_ffi" } sink = { path = "presence/sink" } +test_vector_hkdf = { path = "presence/test_vector_hkdf" } + +# from utils workspace +derive_fuzztest = { path = "../common/derive_fuzztest" } +derive_fuzztest_macro = { path = "../common/derive_fuzztest_macro" } +handle_map = { path = "../common/handle_map" } +lock_adapter = { path = "../common/lock_adapter" } +pourover = { path = "../common/pourover" } +pourover_macro = { path = "../common/pourover_macro" } # from crates.io rand = { version = "0.8.5", default-features = false } @@ -91,10 +99,12 @@ rand_pcg = "0.3.1" sha2 = { version = "0.10.8", default-features = false } aes = "0.8.3" +arbitrary = "1.3.2" cbc = { version = "0.1.2", features = ["block-padding"] } ctr = "0.9.2" hkdf = "0.12.3" hmac = "0.12.1" +nom = { version = "7.1.3", default-features = false } ed25519-dalek = { version = "2.1.0", default-features = false } ed25519 = "2.2.3" aes-gcm = "0.10.3" @@ -144,6 +154,11 @@ syn = { version = "2.0", features = ["full"] } proc-macro2 = "1.0" quote = "1.0" +itertools = "0.12.1" +quickcheck = "1.0.3" +proptest = "1.4.0" +proptest-arbitrary-interop = { git = "https://github.com/brson/proptest-arbitrary-interop.git", branch = "incorrect-format" } +libfuzzer-sys = "0.4.7" [workspace.package] version = "0.1.0" @@ -178,7 +193,7 @@ [dependencies] clap.workspace = true -cmd-runner = { path = "../cmd-runner" } +cmd_runner = { path = "../common/cmd_runner" } anyhow.workspace = true shell-escape = "0.1.5" owo-colors.workspace = true @@ -191,10 +206,10 @@ thiserror.workspace = true log.workspace = true env_logger.workspace = true -which = "4.4.0" file-header = "0.1.2" -serde_json.workspace = true +serde_json = { workspace = true, features = ["std"] } regex = "1.10.2" +xshell = "0.2.6" [dev-dependencies] tempfile.workspace = true
diff --git a/nearby/README.md b/nearby/README.md index 86db67d..f951a8b 100644 --- a/nearby/README.md +++ b/nearby/README.md
@@ -32,10 +32,10 @@ protobuf in order to build correctly. To make the setup of this easier you can use Docker to handle setting up the environment in a container. -First install Docker then build and run the image: +First install Docker then build and run the image from repo root: ``` -sudo docker build -t nearby_rust:v1.0 .. +sudo docker build -t nearby_rust:v1.0 . sudo docker run --rm -it nearby_rust:v1.0 ```
diff --git a/nearby/connections/ukey2/ukey2/src/lib.rs b/nearby/connections/ukey2/ukey2/src/lib.rs index dc17b83..4d64bc8 100644 --- a/nearby/connections/ukey2/ukey2/src/lib.rs +++ b/nearby/connections/ukey2/ukey2/src/lib.rs
@@ -25,6 +25,7 @@ mod tests; mod ukey2_handshake; +pub use proto_adapter::NextProtocol; pub use state_machine::{SendAlert, StateMachine}; pub use ukey2_handshake::{ CompletedHandshake, HandshakeImplementation, Ukey2Client, Ukey2ClientStage1, Ukey2Server,
diff --git a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs index 2986276..0ecbe8a 100644 --- a/nearby/connections/ukey2/ukey2/src/proto_adapter.rs +++ b/nearby/connections/ukey2/ukey2/src/proto_adapter.rs
@@ -17,6 +17,8 @@ use crypto_provider::elliptic_curve::EcdhProvider; use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256}; use crypto_provider::CryptoProvider; +use std::collections::HashSet; +use std::fmt::{Display, Formatter}; use ukey2_proto::ukey2_all_proto::{securemessage, ukey}; /// For generated proto types for UKEY2 messages @@ -71,6 +73,41 @@ fn into_adapter(self) -> Result<A, ukey::ukey2alert::AlertType>; } +/// Enum representing the different supported next_protocol strings, ordered by desirability. +#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)] +#[repr(i32)] +pub enum NextProtocol { + /// AES-256-GCM-SIV, for use with newer clients. + Aes256GcmSiv, + /// AES_256_CBC-HMAC_SHA256, already in use and supported by all clients. + Aes256CbcHmacSha256, +} + +impl TryFrom<&String> for NextProtocol { + type Error = ukey::ukey2alert::AlertType; + + fn try_from(value: &String) -> Result<Self, Self::Error> { + match value.as_str() { + "AES_256_GCM_SIV" => Ok(NextProtocol::Aes256GcmSiv), + "AES_256_CBC-HMAC_SHA256" => Ok(NextProtocol::Aes256CbcHmacSha256), + _ => Err(ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL), + } + } +} + +impl Display for NextProtocol { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + NextProtocol::Aes256CbcHmacSha256 => "AES_256_CBC-HMAC_SHA256", + NextProtocol::Aes256GcmSiv => "AES_256_GCM_SIV", + }, + ) + } +} + #[derive(Debug, PartialEq, Eq)] pub(crate) enum MessageType { ClientInit, @@ -81,7 +118,7 @@ pub(crate) struct ClientInit { version: i32, commitments: Vec<CipherCommitment>, - next_protocol: String, + next_protocols: HashSet<NextProtocol>, } impl ClientInit { @@ -93,8 +130,8 @@ &self.commitments } - pub fn next_protocol(&self) -> &str { - &self.next_protocol + pub fn next_protocols(&self) -> &HashSet<NextProtocol> { + &self.next_protocols } } @@ -104,6 +141,7 @@ random: [u8; 32], handshake_cipher: HandshakeCipher, pub(crate) public_key: Vec<u8>, + selected_next_protocol: NextProtocol, } impl ServerInit { @@ -114,6 +152,10 @@ pub fn handshake_cipher(&self) -> HandshakeCipher { self.handshake_cipher } + + pub fn selected_next_protocol(&self) -> NextProtocol { + self.selected_next_protocol + } } pub(crate) struct ClientFinished { @@ -208,8 +250,13 @@ .next_protocol .filter(|n| !n.is_empty()) .ok_or(ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL)?; + let mut next_protocols: HashSet<NextProtocol> = + HashSet::from([(&next_protocol).try_into()?]); + let other_next_protocols: Vec<NextProtocol> = + self.next_protocols.iter().filter_map(|p| p.try_into().ok()).collect(); + next_protocols.extend(&other_next_protocols); Ok(ClientInit { - next_protocol, + next_protocols, version, commitments: self .cipher_commitments @@ -234,7 +281,11 @@ // We will be handling bad pubkeys in the layers above let public_key: Vec<u8> = self.public_key.ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?; - Ok(ServerInit { handshake_cipher, version, public_key, random }) + let selected_next_protocol = self + .selected_next_protocol + .and_then(|p| (&p).try_into().ok()) + .unwrap_or(NextProtocol::Aes256CbcHmacSha256); + Ok(ServerInit { handshake_cipher, version, public_key, random, selected_next_protocol }) } }
diff --git a/nearby/connections/ukey2/ukey2/src/state_machine.rs b/nearby/connections/ukey2/ukey2/src/state_machine.rs index d2021e6..b4ad360 100644 --- a/nearby/connections/ukey2/ukey2/src/state_machine.rs +++ b/nearby/connections/ukey2/ukey2/src/state_machine.rs
@@ -12,17 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::fmt::Debug; + +use log::error; + +use crypto_provider::CryptoProvider; +use ukey2_proto::protobuf::Message; +use ukey2_proto::ukey2_all_proto::ukey; + use crate::proto_adapter::{IntoAdapter, MessageType, ToWrappedMessage as _}; use crate::ukey2_handshake::ClientFinishedError; use crate::ukey2_handshake::{ ClientInit, ClientInitError, Ukey2Client, Ukey2ClientStage1, Ukey2Server, Ukey2ServerStage1, Ukey2ServerStage2, }; -use crypto_provider::CryptoProvider; -use log::error; -use std::fmt::Debug; -use ukey2_proto::protobuf::Message; -use ukey2_proto::ukey2_all_proto::ukey; /// An alert type and message to be sent to the other party. #[derive(Debug, PartialEq, Eq)]
diff --git a/nearby/connections/ukey2/ukey2/src/tests.rs b/nearby/connections/ukey2/ukey2/src/tests.rs index 92c0358..1b2424a 100644 --- a/nearby/connections/ukey2/ukey2/src/tests.rs +++ b/nearby/connections/ukey2/ukey2/src/tests.rs
@@ -12,22 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(clippy::unwrap_used)] +use std::collections::hash_set; + +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; +use sha2::Digest; use crate::{ proto_adapter::{IntoAdapter as _, MessageType, ToWrappedMessage as _}, ukey2_handshake::HandshakeCipher, - HandshakeImplementation, StateMachine, Ukey2ClientStage1, Ukey2ServerStage1, + HandshakeImplementation, NextProtocol, StateMachine, Ukey2ClientStage1, Ukey2ServerStage1, }; use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey}; use crypto_provider::p256::P256; use crypto_provider::x25519::X25519; use crypto_provider::{CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; -use sha2::Digest; -use std::collections::hash_set; use ukey2_proto::protobuf::Message; use ukey2_proto::ukey2_all_proto::ukey; @@ -39,11 +39,12 @@ <<CryptoProviderImpl as CryptoProvider>::P256 as EcdhProvider<P256>>::EphemeralSecret; #[test] +#[allow(clippy::unwrap_used)] fn advance_from_init_to_finish_client_test() { let mut rng = StdRng::from_entropy(); let client1 = Ukey2ClientStage1::<CryptoProviderImpl>::from( &mut rng, - "next protocol".to_string(), + vec![NextProtocol::Aes256CbcHmacSha256], HandshakeImplementation::Spec, ); @@ -68,6 +69,7 @@ } #[test] +#[allow(clippy::unwrap_used)] fn advance_from_init_to_complete_server_x25519_test() { let mut rng = StdRng::from_entropy(); let mut next_protocols = hash_set::HashSet::new(); @@ -121,6 +123,7 @@ } #[test] +#[allow(clippy::unwrap_used)] fn advance_from_init_to_complete_server_p256_test() { let mut rng = StdRng::from_entropy(); let mut next_protocols = hash_set::HashSet::new(); @@ -182,6 +185,7 @@ } #[test] +#[allow(clippy::unwrap_used)] fn convert_to_message_type() { assert_eq!( MessageType::ClientInit, @@ -198,7 +202,28 @@ } #[test] +#[allow(clippy::unwrap_used)] fn convert_to_cipher_type() { assert_eq!(HandshakeCipher::P256Sha512, 100.into_adapter().unwrap()); assert_eq!(HandshakeCipher::Curve25519Sha512, 200.into_adapter().unwrap()); } + +#[test] +fn convert_next_protocols() { + assert_eq!( + (&"AES_256_CBC-HMAC_SHA256".to_string()).try_into(), + Ok(NextProtocol::Aes256CbcHmacSha256) + ); + assert_eq!((&"AES_256_GCM_SIV".to_string()).try_into(), Ok(NextProtocol::Aes256GcmSiv)); + assert_eq!( + TryInto::<NextProtocol>::try_into(&"Random protocol".to_string()), + Err(ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL) + ); +} + +#[test] +fn sort_next_protocols() { + let mut next_protocols = [NextProtocol::Aes256CbcHmacSha256, NextProtocol::Aes256GcmSiv]; + next_protocols.sort(); + assert_eq!(next_protocols, [NextProtocol::Aes256GcmSiv, NextProtocol::Aes256CbcHmacSha256]) +}
diff --git a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs index 0b2be0e..95d3b92 100644 --- a/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs +++ b/nearby/connections/ukey2/ukey2/src/ukey2_handshake.rs
@@ -16,10 +16,12 @@ // TODO: remove this and convert all unwraps to expects #![allow(clippy::unwrap_used)] -pub(crate) use crate::proto_adapter::{ - CipherCommitment, ClientFinished, ClientInit, GenericPublicKey, HandshakeCipher, - IntoAdapter as _, ServerInit, ToWrappedMessage as _, +use std::{ + collections::HashSet, + fmt::{self, Formatter}, + marker::PhantomData, }; + use crypto_provider::elliptic_curve::EphemeralSecret; use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256}; use crypto_provider::x25519::X25519; @@ -30,14 +32,15 @@ sha2::{Sha256, Sha512}, CryptoRng, }; -use std::{ - collections::hash_set, - fmt::{self, Formatter}, - marker::PhantomData, -}; use ukey2_proto::protobuf::Message; use ukey2_proto::ukey2_all_proto::{securemessage, ukey}; +use crate::proto_adapter::NextProtocol; +pub(crate) use crate::proto_adapter::{ + CipherCommitment, ClientFinished, ClientInit, GenericPublicKey, HandshakeCipher, + IntoAdapter as _, ServerInit, ToWrappedMessage as _, +}; + pub trait WireCompatibilityLayer { fn encode_public_key<C: CryptoProvider>( &self, @@ -145,7 +148,7 @@ } pub struct Ukey2ServerStage1<C: CryptoProvider> { - pub(crate) next_protocols: hash_set::HashSet<String>, + pub(crate) next_protocols: HashSet<NextProtocol>, pub(crate) handshake_impl: HandshakeImplementation, _marker: PhantomData<C>, } @@ -157,11 +160,12 @@ } impl<C: CryptoProvider> Ukey2ServerStage1<C> { - pub fn from( - next_protocols: hash_set::HashSet<String>, - handshake_impl: HandshakeImplementation, - ) -> Self { - Self { next_protocols, handshake_impl, _marker: PhantomData } + pub fn from(next_protocols: HashSet<String>, handshake_impl: HandshakeImplementation) -> Self { + Self { + next_protocols: next_protocols.iter().filter_map(|p| p.try_into().ok()).collect(), + handshake_impl, + _marker: PhantomData, + } } pub(crate) fn handle_client_init<R: rand::Rng + rand::CryptoRng>( @@ -174,10 +178,11 @@ return Err(ClientInitError::BadVersion); } - let next_protocol = client_init.next_protocol(); - if !self.next_protocols.contains(next_protocol) { + let next_protocols = client_init.next_protocols(); + let Some(selected_protocol) = next_protocols.intersection(&self.next_protocols).min() + else { return Err(ClientInitError::BadNextProtocol); - } + }; // nothing to check here about client_init.random -- already been validated as 32 bytes @@ -207,7 +212,7 @@ commitment.clone(), secret, self.handshake_impl, - next_protocol.to_string(), + *selected_protocol, )) } HandshakeCipher::P256Sha512 => { @@ -224,7 +229,7 @@ commitment.clone(), secret, self.handshake_impl, - next_protocol.to_string(), + *selected_protocol, )) } } @@ -242,7 +247,7 @@ commitment: CipherCommitment, key_pair: ServerKeyPair<C>, pub(crate) handshake_impl: HandshakeImplementation, - next_protocol: String, + next_protocol: NextProtocol, _marker: PhantomData<C>, } @@ -262,7 +267,7 @@ commitment: CipherCommitment, key_pair: ServerKeyPair<C>, handshake_impl: HandshakeImplementation, - next_protocol: String, + next_protocol: NextProtocol, ) -> Self { let random: [u8; 32] = rng.gen(); let mut server_init = ukey::Ukey2ServerInit::default(); @@ -278,6 +283,7 @@ ) .unwrap(), }); + server_init.set_selected_next_protocol(next_protocol.to_string()); Self { client_init_msg, @@ -372,7 +378,7 @@ client_init_bytes: Vec<u8>, commitment_ciphers: Vec<HandshakeCipher>, handshake_impl: HandshakeImplementation, - next_protocol: String, + next_protocols: Vec<NextProtocol>, _marker: PhantomData<C>, } @@ -383,11 +389,15 @@ } impl<C: CryptoProvider> Ukey2ClientStage1<C> { + // Clippy: we assert that there must be at least one element in `next_protocols`, so indexing + // [0] is safe. + #[allow(clippy::indexing_slicing)] pub fn from<R: rand::Rng + rand::SeedableRng + rand::CryptoRng>( rng: &mut R, - next_protocol: String, + next_protocols: Vec<NextProtocol>, handshake_impl: HandshakeImplementation, ) -> Self { + assert!(!next_protocols.is_empty()); let random = rng.gen::<[u8; 32]>().to_vec(); // Curve25519 ClientFinished Message let curve25519_secret = @@ -408,10 +418,10 @@ // P256 ClientFinished Message let p256_secret = <C::P256 as EcdhProvider<P256>>::EphemeralSecret::generate_random( - &mut<<<C::P256 as EcdhProvider<P256>>::EphemeralSecret as EphemeralSecret< - P256, - >>::Rng as CryptoRng>::new(), - ); + &mut <<<C::P256 as EcdhProvider<P256>>::EphemeralSecret as EphemeralSecret< + P256, + >>::Rng as CryptoRng>::new(), + ); let p256_client_finished_bytes = { let client_finished = ukey::Ukey2ClientFinished { public_key: Some( @@ -446,7 +456,8 @@ version: Some(1), random: Some(random), cipher_commitments: vec![curve25519_commitment, p256_commitment], - next_protocol: Some(next_protocol.to_string()), + next_protocol: Some(next_protocols[0].to_string()), + next_protocols: next_protocols.iter().map(|x| x.to_string()).collect(), ..Default::default() }; client_init.to_wrapped_msg().write_to_bytes().unwrap() @@ -463,7 +474,7 @@ HandshakeCipher::P256Sha512, ], handshake_impl, - next_protocol, + next_protocols, _marker: PhantomData, } } @@ -481,6 +492,11 @@ return Err(ServerInitError::BadVersion); } + if !self.next_protocols.contains(&server_init.selected_next_protocol()) { + return Err(ServerInitError::BadNextProtocol); + } + let next_protocol = server_init.selected_next_protocol(); + // loop over all commitments every time for a semblance of constant time-ness let server_cipher = self .commitment_ciphers @@ -537,7 +553,7 @@ self.client_init_bytes, server_init_bytes.to_vec(), shared_secret_bytes, - self.next_protocol, + next_protocol, ), }) } @@ -551,6 +567,8 @@ BadPublicKey, /// The diffie-hellman key exchange failed to generate a shared secret BadKeyExchange, + /// The server sent an invalid next protocol that is not available to the client. + BadNextProtocol, } #[derive(Clone)] @@ -596,7 +614,7 @@ client_init_bytes: Vec<u8>, server_init_bytes: Vec<u8>, shared_secret: Vec<u8>, - pub next_protocol: String, + pub next_protocol: NextProtocol, } impl CompletedHandshake { @@ -604,7 +622,7 @@ client_init_bytes: Vec<u8>, server_init_bytes: Vec<u8>, shared_secret: Vec<u8>, - next_protocol: String, + next_protocol: NextProtocol, ) -> Self { Self { client_init_bytes, server_init_bytes, shared_secret, next_protocol } }
diff --git a/nearby/connections/ukey2/ukey2/tests/tests.rs b/nearby/connections/ukey2/ukey2/tests/tests.rs index 85b972c..d0acacf 100644 --- a/nearby/connections/ukey2/ukey2/tests/tests.rs +++ b/nearby/connections/ukey2/ukey2/tests/tests.rs
@@ -21,9 +21,8 @@ #[test] fn full_integration_state_machine() { - let mut next_protocols = hash_set::HashSet::new(); - let next_protocol = "AES_256_CBC-HMAC_SHA256".to_string(); - let _ = next_protocols.insert(next_protocol.clone()); + let next_protocol = NextProtocol::Aes256CbcHmacSha256; + let next_protocols = hash_set::HashSet::from([next_protocol.to_string()]); let server1 = Ukey2ServerStage1::<CryptoProviderImpl>::from( next_protocols, HandshakeImplementation::Spec, @@ -31,7 +30,7 @@ let mut rng = StdRng::from_entropy(); let client1 = Ukey2ClientStage1::<CryptoProviderImpl>::from( &mut rng, - next_protocol, + vec![next_protocol], HandshakeImplementation::Spec, ); let server2 = server1.advance_state(&mut rng, client1.client_init_msg()).unwrap(); @@ -58,9 +57,8 @@ #[test] fn full_integration_state_machine_public_key_in_protobuf() { - let mut next_protocols = hash_set::HashSet::new(); - let next_protocol = "AES_256_CBC-HMAC_SHA256".to_string(); - let _ = next_protocols.insert(next_protocol.clone()); + let next_protocol = NextProtocol::Aes256CbcHmacSha256; + let next_protocols = hash_set::HashSet::from([next_protocol.to_string()]); let server1 = Ukey2ServerStage1::<CryptoProviderImpl>::from( next_protocols, HandshakeImplementation::PublicKeyInProtobuf, @@ -68,7 +66,7 @@ let mut rng = StdRng::from_entropy(); let client1 = Ukey2ClientStage1::<CryptoProviderImpl>::from( &mut rng, - next_protocol, + vec![next_protocol], HandshakeImplementation::PublicKeyInProtobuf, ); let server2 = server1.advance_state(&mut rng, client1.client_init_msg()).unwrap(); @@ -92,3 +90,79 @@ .derive_array::<32>() ); } + +#[test] +fn full_integration_state_machine_multiple_next_protocols_sort() { + let raw_next_protocols = [NextProtocol::Aes256CbcHmacSha256, NextProtocol::Aes256GcmSiv]; + let next_protocols = hash_set::HashSet::from(raw_next_protocols.map(|p| p.to_string())); + let server1 = Ukey2ServerStage1::<CryptoProviderImpl>::from( + next_protocols, + HandshakeImplementation::Spec, + ); + let mut rng = StdRng::from_entropy(); + let client1 = Ukey2ClientStage1::<CryptoProviderImpl>::from( + &mut rng, + raw_next_protocols.to_vec(), + HandshakeImplementation::Spec, + ); + let server2 = server1.advance_state(&mut rng, client1.client_init_msg()).unwrap(); + + let client2 = client1.advance_state(&mut rng, server2.server_init_msg()).unwrap(); + + let server3 = server2.advance_state(&mut rng, client2.client_finished_msg()).unwrap(); + + assert_eq!( + server3.completed_handshake().auth_string::<CryptoProviderImpl>().derive_array::<32>(), + client2.completed_handshake().auth_string::<CryptoProviderImpl>().derive_array::<32>() + ); + assert_eq!( + server3 + .completed_handshake() + .next_protocol_secret::<CryptoProviderImpl>() + .derive_array::<32>(), + client2 + .completed_handshake() + .next_protocol_secret::<CryptoProviderImpl>() + .derive_array::<32>() + ); + assert_eq!(server3.completed_handshake().next_protocol, NextProtocol::Aes256GcmSiv); + assert_eq!(client2.completed_handshake().next_protocol, NextProtocol::Aes256GcmSiv); +} + +#[test] +fn full_integration_state_machine_multiple_next_protocols_client() { + let raw_next_protocols = [NextProtocol::Aes256CbcHmacSha256, NextProtocol::Aes256GcmSiv]; + let next_protocols = hash_set::HashSet::from(raw_next_protocols.map(|p| p.to_string())); + let server1 = Ukey2ServerStage1::<CryptoProviderImpl>::from( + next_protocols, + HandshakeImplementation::Spec, + ); + let mut rng = StdRng::from_entropy(); + let client1 = Ukey2ClientStage1::<CryptoProviderImpl>::from( + &mut rng, + [NextProtocol::Aes256CbcHmacSha256].to_vec(), + HandshakeImplementation::Spec, + ); + let server2 = server1.advance_state(&mut rng, client1.client_init_msg()).unwrap(); + + let client2 = client1.advance_state(&mut rng, server2.server_init_msg()).unwrap(); + + let server3 = server2.advance_state(&mut rng, client2.client_finished_msg()).unwrap(); + + assert_eq!( + server3.completed_handshake().auth_string::<CryptoProviderImpl>().derive_array::<32>(), + client2.completed_handshake().auth_string::<CryptoProviderImpl>().derive_array::<32>() + ); + assert_eq!( + server3 + .completed_handshake() + .next_protocol_secret::<CryptoProviderImpl>() + .derive_array::<32>(), + client2 + .completed_handshake() + .next_protocol_secret::<CryptoProviderImpl>() + .derive_array::<32>() + ); + assert_eq!(server3.completed_handshake().next_protocol, NextProtocol::Aes256CbcHmacSha256); + assert_eq!(client2.completed_handshake().next_protocol, NextProtocol::Aes256CbcHmacSha256); +}
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml b/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml index f302119..1034359 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml +++ b/nearby/connections/ukey2/ukey2_c_ffi/Cargo.toml
@@ -6,7 +6,6 @@ [dependencies] ukey2_connections = { path = "../ukey2_connections" } -ukey2_rs = { path = "../ukey2" } cfg-if.workspace = true crypto_provider_default.workspace = true lock_adapter = {workspace = true, features = ["spin"]}
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_bindings.h b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_bindings.h index e1f7e1e..e19aa68 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_bindings.h +++ b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_bindings.h
@@ -64,13 +64,20 @@ // Common handshake methods bool is_handshake_complete(Ukey2HandshakeContextHandle handle); RustFFIByteArray get_next_handshake_message(Ukey2HandshakeContextHandle handle); -CMessageParseResult parse_handshake_message(Ukey2HandshakeContextHandle handle, CFFIByteArray message); -Ukey2ConnectionContextHandle to_connection_context(Ukey2HandshakeContextHandle handle); -RustFFIByteArray get_verification_string(Ukey2HandshakeContextHandle handle, size_t output_length); +CMessageParseResult parse_handshake_message(Ukey2HandshakeContextHandle handle, + CFFIByteArray message); +Ukey2ConnectionContextHandle to_connection_context( + Ukey2HandshakeContextHandle handle); +RustFFIByteArray get_verification_string(Ukey2HandshakeContextHandle handle, + size_t output_length); // D2DConnectionContextV1 methods -RustFFIByteArray encode_message_to_peer(Ukey2ConnectionContextHandle handle, CFFIByteArray message, CFFIByteArray associated_data); -RustFFIByteArray decode_message_from_peer(Ukey2ConnectionContextHandle handle, CFFIByteArray message, CFFIByteArray associated_data); +RustFFIByteArray encode_message_to_peer(Ukey2ConnectionContextHandle handle, + CFFIByteArray message, + CFFIByteArray associated_data); +RustFFIByteArray decode_message_from_peer(Ukey2ConnectionContextHandle handle, + CFFIByteArray message, + CFFIByteArray associated_data); RustFFIByteArray get_session_unique(Ukey2ConnectionContextHandle handle); int get_sequence_number_for_encoding(Ukey2ConnectionContextHandle handle); int get_sequence_number_for_decoding(Ukey2ConnectionContextHandle handle);
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_ffi.h b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_ffi.h index 654e293..457286d 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_ffi.h +++ b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_ffi.h
@@ -11,80 +11,88 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -#include "ukey2_bindings.h" +#pragma once #include <string> +#include "ukey2_bindings.h" + +namespace rust { struct D2DRestoreConnectionContextV1Result; -// The Connection object that can handle encryption/decryption of messages over the wire. -// This object should only be constructed via FromSavedSession() or Ukey2Handshake::ToConnectionContext(). +// The Connection object that can handle encryption/decryption of messages over +// the wire. This object should only be constructed via FromSavedSession() or +// Ukey2Handshake::ToConnectionContext(). class D2DConnectionContextV1 { - public: - // Encodes a message to the connection peer using the derived key from the handshake - // If associated_data is not empty, it will be used to compute the signature and the same - // associated_data string must be passed into DecodeMessageFromPeer() in order for the - // message to be validated. - std::string EncodeMessageToPeer(std::string message, std::string associated_data); - // Decodes a message from the connection peer. If associated_data was passed into - // EncodeMessageToPeer(), that same associated_data must be passed here in order for - // this function to succeed. - std::string DecodeMessageFromPeer(std::string message, std::string associated_data); - // Gets a session-specific unique identifier. - std::string GetSessionUnique(); - // Gets the encoding sequence number. - int GetSequenceNumberForEncoding(); - // Gets the decoding sequence number. - int GetSequenceNumberForDecoding(); - // Returns byte data suitable for use with FromSavedSession(). - std::string SaveSession(); - // Recreates the state of a previous D2DConnectionContextV1 using the data from SaveSession(). - // This function will return an error if the byte pattern is not as expected. - // Expected format: - // ------------------------------------------------------------------------------------------- - // | 1 byte | 4 bytes | 4 bytes | 32 bytes | 32 bytes | - // ------------------------------------------------------------------------------------------- - // Protocol version | Encode sequence number | Decode sequence number | Encode key | Decode key - // (always 1) - static D2DRestoreConnectionContextV1Result FromSavedSession(std::string data); + public: + // Encodes a message to the connection peer using the derived key from the + // handshake If associated_data is not empty, it will be used to compute the + // signature and the same associated_data string must be passed into + // DecodeMessageFromPeer() in order for the message to be validated. + std::string EncodeMessageToPeer(std::string message, + std::string associated_data); + // Decodes a message from the connection peer. If associated_data was passed + // into EncodeMessageToPeer(), that same associated_data must be passed here + // in order for this function to succeed. + std::string DecodeMessageFromPeer(std::string message, + std::string associated_data); + // Gets a session-specific unique identifier. + std::string GetSessionUnique(); + // Gets the encoding sequence number. + int GetSequenceNumberForEncoding(); + // Gets the decoding sequence number. + int GetSequenceNumberForDecoding(); + // Returns byte data suitable for use with FromSavedSession(). + std::string SaveSession(); + // Recreates the state of a previous D2DConnectionContextV1 using the data + // from SaveSession(). This function will return an error if the byte pattern + // is not as expected. Expected format: + // --------------------------------------------------------------------------- + // | 1 byte | 4 bytes | 4 bytes | 32 bytes | 32 bytes | + // --------------------------------------------------------------------------- + // Version | Encode sequence # | Decode sequence # | Encode key | Decode key + static D2DRestoreConnectionContextV1Result FromSavedSession(std::string data); - private: - friend class Ukey2Handshake; - D2DConnectionContextV1(Ukey2ConnectionContextHandle handle) : handle_(handle) {} - const Ukey2ConnectionContextHandle handle_; + private: + friend class Ukey2Handshake; + D2DConnectionContextV1(Ukey2ConnectionContextHandle handle) + : handle_(handle) {} + const Ukey2ConnectionContextHandle handle_; }; struct D2DRestoreConnectionContextV1Result { - D2DConnectionContextV1 handle; - CD2DRestoreConnectionContextV1Status status; + D2DConnectionContextV1 handle; + CD2DRestoreConnectionContextV1Status status; }; struct ParseResult { - bool success; - std::string alert_to_send; + bool success; + std::string alert_to_send; }; -// Base handshake. This should be used to start a secure channel represented by a D2DConnectionContextV1. +// Base handshake. This should be used to start a secure channel represented by +// a D2DConnectionContextV1. class Ukey2Handshake { - public: - // Creates a Ukey2Handshake instance for the responder. - static Ukey2Handshake ForResponder(); - // Creates a Ukey2Handshake instance for the initiator. - static Ukey2Handshake ForInitiator(); - // Returns true if the handshake is complete, false otherwise. - bool IsHandshakeComplete(); - // Returns raw byte data with the message to send over the wire. - std::string GetNextHandshakeMessage(); - // Parses the raw handshake message received over the wire. - ParseResult ParseHandshakeMessage(std::string message); - // Returns the authentication string of length output_length to be confirmed on both devices. - std::string GetVerificationString(size_t output_length); - // Turns this Ukey2Handshake instance into a D2DConnectionContextV1. This method once called, - // renders the Ukey2Handshake object unusable. - D2DConnectionContextV1 ToConnectionContext(); + public: + // Creates a Ukey2Handshake instance for the responder. + static Ukey2Handshake ForResponder(); + // Creates a Ukey2Handshake instance for the initiator. + static Ukey2Handshake ForInitiator(); + // Returns true if the handshake is complete, false otherwise. + bool IsHandshakeComplete(); + // Returns raw byte data with the message to send over the wire. + std::string GetNextHandshakeMessage(); + // Parses the raw handshake message received over the wire. + ParseResult ParseHandshakeMessage(std::string message); + // Returns the authentication string of length output_length to be confirmed + // on both devices. + std::string GetVerificationString(size_t output_length); + // Turns this Ukey2Handshake instance into a D2DConnectionContextV1. This + // method once called, renders the Ukey2Handshake object unusable. + D2DConnectionContextV1 ToConnectionContext(); - private: - Ukey2Handshake(Ukey2HandshakeContextHandle handle) : handle_(handle) {} - const Ukey2HandshakeContextHandle handle_; + private: + Ukey2Handshake(Ukey2HandshakeContextHandle handle) : handle_(handle) {} + const Ukey2HandshakeContextHandle handle_; }; +} // namespace rust
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_glue.cc b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_glue.cc index 6b03f1c..354112c 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_glue.cc +++ b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_glue.cc
@@ -12,139 +12,143 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ukey2_bindings.h" -#include "ukey2_ffi.h" - #include <cassert> #include <cstring> #include <iostream> #include <string> +#include "ukey2_bindings.h" +#include "ukey2_ffi.h" + CFFIByteArray nullByteArray() { - return { - .handle = nullptr, - .len = 0, - }; + return { + .handle = nullptr, + .len = 0, + }; } // Implementation of functions -Ukey2Handshake Ukey2Handshake::ForInitiator() { - return Ukey2Handshake(initiator_new()); +rust::Ukey2Handshake rust::Ukey2Handshake::ForInitiator() { + return Ukey2Handshake(initiator_new()); } -Ukey2Handshake Ukey2Handshake::ForResponder() { - return Ukey2Handshake(responder_new()); +rust::Ukey2Handshake rust::Ukey2Handshake::ForResponder() { + return Ukey2Handshake(responder_new()); } -bool Ukey2Handshake::IsHandshakeComplete() { - return is_handshake_complete(handle_); +bool rust::Ukey2Handshake::IsHandshakeComplete() { + return is_handshake_complete(handle_); } -std::string Ukey2Handshake::GetNextHandshakeMessage() { - RustFFIByteArray array = get_next_handshake_message(handle_); - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::Ukey2Handshake::GetNextHandshakeMessage() { + RustFFIByteArray array = get_next_handshake_message(handle_); + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -ParseResult Ukey2Handshake::ParseHandshakeMessage(std::string message) { - CFFIByteArray messageRaw{ - .handle = (uint8_t*)message.c_str(), - .len = message.length(), - }; - CMessageParseResult result = parse_handshake_message(handle_, messageRaw); - std::string alert; - if (!result.success) { - std::cout << "parse failed" << std::endl; - RustFFIByteArray array = result.alert_to_send; - if (array.handle != nullptr) { - alert = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - } +rust::ParseResult rust::Ukey2Handshake::ParseHandshakeMessage( + std::string message) { + CFFIByteArray messageRaw{ + .handle = (uint8_t*)message.c_str(), + .len = message.length(), + }; + CMessageParseResult result = parse_handshake_message(handle_, messageRaw); + std::string alert; + if (!result.success) { + std::cout << "parse failed" << std::endl; + RustFFIByteArray array = result.alert_to_send; + if (array.handle != nullptr) { + alert = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); } - return ParseResult { - .success = result.success, - .alert_to_send = alert, - }; + } + return ParseResult{ + .success = result.success, + .alert_to_send = alert, + }; } -std::string Ukey2Handshake::GetVerificationString(size_t output_length) { - RustFFIByteArray array = get_verification_string(handle_, output_length); - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::Ukey2Handshake::GetVerificationString(size_t output_length) { + RustFFIByteArray array = get_verification_string(handle_, output_length); + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -D2DConnectionContextV1 Ukey2Handshake::ToConnectionContext() { - assert(IsHandshakeComplete()); - return D2DConnectionContextV1(to_connection_context(handle_)); +rust::D2DConnectionContextV1 rust::Ukey2Handshake::ToConnectionContext() { + assert(IsHandshakeComplete()); + return D2DConnectionContextV1(to_connection_context(handle_)); } -std::string D2DConnectionContextV1::DecodeMessageFromPeer(std::string message, std::string associated_data) { - CFFIByteArray messageRaw{ - .handle = (uint8_t*)message.c_str(), - .len = message.length(), - }; - CFFIByteArray associatedDataRaw{ - .handle = (uint8_t*)associated_data.c_str(), - .len = associated_data.length(), - }; - RustFFIByteArray array = - decode_message_from_peer(handle_, messageRaw, associatedDataRaw); - if (array.handle == nullptr) { - return ""; - } - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::D2DConnectionContextV1::DecodeMessageFromPeer( + std::string message, std::string associated_data) { + CFFIByteArray messageRaw{ + .handle = (uint8_t*)message.c_str(), + .len = message.length(), + }; + CFFIByteArray associatedDataRaw{ + .handle = (uint8_t*)associated_data.c_str(), + .len = associated_data.length(), + }; + RustFFIByteArray array = + decode_message_from_peer(handle_, messageRaw, associatedDataRaw); + if (array.handle == nullptr) { + return ""; + } + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -std::string D2DConnectionContextV1::EncodeMessageToPeer(std::string message, std::string associated_data) { - CFFIByteArray messageRaw{ - .handle = (uint8_t*)message.c_str(), - .len = message.length(), - }; - CFFIByteArray associatedDataRaw{ - .handle = (uint8_t*)associated_data.c_str(), - .len = associated_data.length(), - }; - RustFFIByteArray array = - encode_message_to_peer(handle_, messageRaw, associatedDataRaw); - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::D2DConnectionContextV1::EncodeMessageToPeer( + std::string message, std::string associated_data) { + CFFIByteArray messageRaw{ + .handle = (uint8_t*)message.c_str(), + .len = message.length(), + }; + CFFIByteArray associatedDataRaw{ + .handle = (uint8_t*)associated_data.c_str(), + .len = associated_data.length(), + }; + RustFFIByteArray array = + encode_message_to_peer(handle_, messageRaw, associatedDataRaw); + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -std::string D2DConnectionContextV1::GetSessionUnique() { - RustFFIByteArray array = get_session_unique(handle_); - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::D2DConnectionContextV1::GetSessionUnique() { + RustFFIByteArray array = get_session_unique(handle_); + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -int D2DConnectionContextV1::GetSequenceNumberForEncoding() { - return get_sequence_number_for_encoding(handle_); +int rust::D2DConnectionContextV1::GetSequenceNumberForEncoding() { + return get_sequence_number_for_encoding(handle_); } -int D2DConnectionContextV1::GetSequenceNumberForDecoding() { - return get_sequence_number_for_decoding(handle_); +int rust::D2DConnectionContextV1::GetSequenceNumberForDecoding() { + return get_sequence_number_for_decoding(handle_); } -std::string D2DConnectionContextV1::SaveSession() { - RustFFIByteArray array = save_session(handle_); - std::string ret = std::string((const char*) array.handle, array.len); - rust_dealloc_ffi_byte_array(array); - return ret; +std::string rust::D2DConnectionContextV1::SaveSession() { + RustFFIByteArray array = save_session(handle_); + std::string ret = std::string((const char*)array.handle, array.len); + rust_dealloc_ffi_byte_array(array); + return ret; } -D2DRestoreConnectionContextV1Result D2DConnectionContextV1::FromSavedSession(std::string data) { - CFFIByteArray arr{ - .handle = (uint8_t*)data.c_str(), - .len = data.length(), - }; - auto result = from_saved_session(arr); - return { - D2DConnectionContextV1(result.handle), - result.status, - }; +rust::D2DRestoreConnectionContextV1Result +rust::D2DConnectionContextV1::FromSavedSession(std::string data) { + CFFIByteArray arr{ + .handle = (uint8_t*)data.c_str(), + .len = data.length(), + }; + auto result = from_saved_session(arr); + return { + D2DConnectionContextV1(result.handle), + result.status, + }; }
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_test.cc b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_test.cc index 962ada8..1a23278 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_test.cc +++ b/nearby/connections/ukey2/ukey2_c_ffi/cpp/ukey2_test.cc
@@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ukey2_ffi.h" - #include <string> #include "gtest/gtest.h" +#include "ukey2_ffi.h" +namespace rust { namespace { -void RunHandshake(Ukey2Handshake initiator_handle, Ukey2Handshake responder_handle) { +void RunHandshake(Ukey2Handshake initiator_handle, + Ukey2Handshake responder_handle) { ParseResult parse_result = responder_handle.ParseHandshakeMessage( initiator_handle.GetNextHandshakeMessage()); ASSERT_TRUE(parse_result.success); @@ -87,3 +88,4 @@ } } // namespace +} // namespace rust
diff --git a/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs b/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs index e5cc548..77d9b59 100644 --- a/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs +++ b/nearby/connections/ukey2/ukey2_c_ffi/src/lib.rs
@@ -25,11 +25,11 @@ #[cfg(not(feature = "std"))] use lock_adapter::spin::Mutex; #[cfg(feature = "std")] -use lock_adapter::std::Mutex; +use lock_adapter::stdlib::Mutex; use ukey2_connections::{ D2DConnectionContextV1, D2DHandshakeContext, HandleMessageError, HandshakeImplementation, - InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, + InitiatorD2DHandshakeContext, NextProtocol, ServerD2DHandshakeContext, }; #[repr(C)] @@ -188,6 +188,7 @@ pub extern "C" fn responder_new() -> u64 { let ctx = Box::new(ServerD2DHandshakeContext::<CryptoProvider>::new( HandshakeImplementation::PublicKeyInProtobuf, + &[NextProtocol::Aes256CbcHmacSha256], )); insert_gen_handle(ctx) } @@ -200,6 +201,7 @@ pub extern "C" fn initiator_new() -> u64 { let ctx = Box::new(InitiatorD2DHandshakeContext::<CryptoProvider>::new( HandshakeImplementation::PublicKeyInProtobuf, + vec![NextProtocol::Aes256CbcHmacSha256], )); insert_gen_handle(ctx) }
diff --git a/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs b/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs index f816165..8c55d23 100644 --- a/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs +++ b/nearby/connections/ukey2/ukey2_connections/benches/ukey2_benches.rs
@@ -23,10 +23,11 @@ D2DConnectionContextV1, D2DHandshakeContext, InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, }; -use ukey2_rs::HandshakeImplementation; +use ukey2_rs::{HandshakeImplementation, NextProtocol}; fn run_handshake_with_rng<C, R>( mut rng: R, + next_protocols: Vec<NextProtocol>, ) -> (D2DConnectionContextV1<R>, D2DConnectionContextV1<R>) where C: CryptoProvider, @@ -35,10 +36,12 @@ let mut initiator_ctx = InitiatorD2DHandshakeContext::<C, R>::new_impl( HandshakeImplementation::Spec, R::from_rng(&mut rng).unwrap(), + next_protocols.clone(), ); let mut server_ctx = ServerD2DHandshakeContext::<C, R>::new_impl( HandshakeImplementation::Spec, R::from_rng(&mut rng).unwrap(), + &next_protocols, ); server_ctx .handle_handshake_message( @@ -60,27 +63,61 @@ (initiator_ctx.to_connection_context().unwrap(), server_ctx.to_connection_context().unwrap()) } -fn criterion_benchmark(c: &mut Criterion) { +fn cbc_criterion_benchmark(c: &mut Criterion) { let kib = 1024; let mut group = c.benchmark_group("throughput"); let mut plaintext = Vec::new(); - let (mut initiator_ctx, mut server_ctx) = - run_handshake_with_rng::<CryptoProviderImpl, _>(rand::rngs::StdRng::from_entropy()); + let (mut initiator_ctx, mut server_ctx) = run_handshake_with_rng::<CryptoProviderImpl, _>( + rand::rngs::StdRng::from_entropy(), + vec![NextProtocol::Aes256CbcHmacSha256], + ); for len in [10 * kib, 1024 * kib] { let _ = group.throughput(Throughput::Bytes(len as u64)); plaintext.resize(len, 0); rand::thread_rng().fill(&mut plaintext[..]); - let _ = group.bench_function(format!("UKEY2 encrypt/decrypt {}KiB", len / kib), |b| { - b.iter(|| { - let msg = initiator_ctx - .encode_message_to_peer::<CryptoProviderImpl, &[u8]>(&plaintext, None); - black_box( - server_ctx.decode_message_from_peer::<CryptoProviderImpl, &[u8]>(&msg, None), - ) - }) - }); + let _ = group.bench_function( + format!("AES-CBC-256_HMAC-SHA256 UKEY2 encrypt/decrypt {}KiB", len / kib), + |b| { + b.iter(|| { + let msg = initiator_ctx + .encode_message_to_peer::<CryptoProviderImpl, &[u8]>(&plaintext, None); + black_box( + server_ctx + .decode_message_from_peer::<CryptoProviderImpl, &[u8]>(&msg, None), + ) + }) + }, + ); } } -criterion_group!(benches, criterion_benchmark); +fn gcm_criterion_benchmark(c: &mut Criterion) { + let kib = 1024; + let mut group = c.benchmark_group("throughput"); + let mut plaintext = Vec::new(); + let (mut initiator_ctx, mut server_ctx) = run_handshake_with_rng::<CryptoProviderImpl, _>( + rand::rngs::StdRng::from_entropy(), + vec![NextProtocol::Aes256GcmSiv], + ); + for len in [10 * kib, 1024 * kib] { + let _ = group.throughput(Throughput::Bytes(len as u64)); + plaintext.resize(len, 0); + rand::thread_rng().fill(&mut plaintext[..]); + let _ = group.bench_function( + format!("AES-GCM-SIV UKEY2 encrypt/decrypt {}KiB", len / kib), + |b| { + b.iter(|| { + let msg = initiator_ctx + .encode_message_to_peer::<CryptoProviderImpl, &[u8]>(&plaintext, None); + black_box( + server_ctx + .decode_message_from_peer::<CryptoProviderImpl, &[u8]>(&msg, None), + ) + }) + }, + ); + } +} + +criterion_group!(benches, cbc_criterion_benchmark, gcm_criterion_benchmark); criterion_main!(benches);
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.toml b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.toml index b8a1295..2c94ebb 100644 --- a/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.toml +++ b/nearby/connections/ukey2/ukey2_connections/fuzz/Cargo.toml
@@ -1,43 +1,34 @@ [package] name = "ukey2_connections-fuzz" -version = "0.0.0" -publish = false -edition = "2021" +version.workspace = true +publish.workspace = true +edition.workspace = true [package.metadata] cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4" -crypto_provider_rustcrypto = { path = "../../../../crypto/crypto_provider_rustcrypto" } -ukey2_rs = { path = "../../ukey2" } -rand_chacha = "0.3.1" -arbitrary = { version = "1.2.3", features = ["derive"] } +arbitrary = { workspace = true, features = ["derive"] } +crypto_provider_rustcrypto.workspace = true +derive_fuzztest.workspace = true +rand_chacha.workspace = true +ukey2_connections.workspace = true +ukey2_rs.workspace = true -[dependencies.ukey2_connections] -path = ".." - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[profile.release] -debug = 1 +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true [[bin]] name = "fuzz_connection" path = "fuzz_targets/fuzz_connection.rs" -test = false doc = false [[bin]] name = "fuzz_handshake" path = "fuzz_targets/fuzz_handshake.rs" -test = false doc = false [[bin]] name = "fuzz_from_saved_session" path = "fuzz_targets/fuzz_from_saved_session.rs" -test = false doc = false
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs index 1db7e63..8a02bc0 100644 --- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs +++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_connection.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,14 +15,15 @@ use arbitrary::Arbitrary; use crypto_provider_rustcrypto::RustCrypto; -use libfuzzer_sys::fuzz_target; +use derive_fuzztest::fuzztest; use rand_chacha::rand_core::SeedableRng; use ukey2_connections::HandshakeImplementation; use ukey2_connections::{ D2DHandshakeContext, InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, }; +use ukey2_rs::NextProtocol; -#[derive(Debug, Arbitrary)] +#[derive(Clone, Debug, Arbitrary)] enum Type { SentByInitiator, SentByServer, @@ -30,28 +31,24 @@ ReceivedByServer, } -#[derive(Debug, Arbitrary)] -struct Message<'a> { +#[derive(Clone, Debug, Arbitrary)] +struct Message { sender: Type, - payload: &'a [u8], - associated_data: Option<&'a [u8]>, + payload: Vec<u8>, + associated_data: Option<Vec<u8>>, } -#[derive(Debug, Arbitrary)] -struct FuzzInput<'a> { - client_rng_seed: [u8; 32], - server_rng_seed: [u8; 32], - messages: Vec<Message<'a>>, -} - -fuzz_target!(|input: FuzzInput| { +#[fuzztest] +fn test(client_rng_seed: [u8; 32], server_rng_seed: [u8; 32], messages: Vec<Message>) { let mut initiator_ctx = InitiatorD2DHandshakeContext::<RustCrypto, _>::new_impl( HandshakeImplementation::Spec, - rand_chacha::ChaChaRng::from_seed(input.client_rng_seed), + rand_chacha::ChaChaRng::from_seed(client_rng_seed), + vec![NextProtocol::Aes256CbcHmacSha256], ); let mut server_ctx = ServerD2DHandshakeContext::<RustCrypto, _>::new_impl( HandshakeImplementation::Spec, - rand_chacha::ChaChaRng::from_seed(input.server_rng_seed), + rand_chacha::ChaChaRng::from_seed(server_rng_seed), + &[NextProtocol::Aes256CbcHmacSha256], ); let client_init = initiator_ctx .get_next_handshake_message() @@ -81,39 +78,40 @@ "Initator handshake context should be converted to connection context successfully", ); - for Message { - sender, - payload, - associated_data, - } in input.messages - { + for Message { sender, payload, associated_data } in messages { match sender { Type::SentByInitiator => { let ciphertext = initiator_connection - .encode_message_to_peer::<RustCrypto, _>(payload, associated_data); + .encode_message_to_peer::<RustCrypto, _>(&payload, associated_data.as_ref()); let decoded = server_connection - .decode_message_from_peer::<RustCrypto, _>(&ciphertext, associated_data) + .decode_message_from_peer::<RustCrypto, _>( + &ciphertext, + associated_data.as_ref(), + ) .unwrap(); assert_eq!(decoded, payload); } Type::SentByServer => { let ciphertext = server_connection - .encode_message_to_peer::<RustCrypto, _>(payload, associated_data); + .encode_message_to_peer::<RustCrypto, _>(&payload, associated_data.as_ref()); let decoded = initiator_connection - .decode_message_from_peer::<RustCrypto, _>(&ciphertext, associated_data) + .decode_message_from_peer::<RustCrypto, _>( + &ciphertext, + associated_data.as_ref(), + ) .unwrap(); assert_eq!(decoded, payload); } Type::ReceivedByInitiator => { // Both Ok and Err results are possible here since the input is Arbitrary payload let _unused_result = initiator_connection - .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data); + .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data.as_ref()); } Type::ReceivedByServer => { // Both Ok and Err results are possible here since the input is Arbitrary payload let _unused_result = server_connection - .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data); + .decode_message_from_peer::<RustCrypto, _>(&payload, associated_data.as_ref()); } } } -}); +}
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs index c2cd385..0d35f7e 100644 --- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs +++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_from_saved_session.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,17 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use libfuzzer_sys::fuzz_target; -use ukey2_connections::{D2DConnectionContextV1, DeserializeError}; use crypto_provider_rustcrypto::RustCrypto; +use derive_fuzztest::fuzztest; +use ukey2_connections::{D2DConnectionContextV1, DeserializeError}; const PROTOCOL_VERSION: u8 = 1; -fuzz_target!(|input: [u8; 73]| { +#[fuzztest] +fn test(input: [u8; 73]) { let result = D2DConnectionContextV1::from_saved_session::<RustCrypto>(&input); if input[0] != PROTOCOL_VERSION { assert_eq!(result.unwrap_err(), DeserializeError::BadProtocolVersion); } else { assert!(result.is_ok()); } -}); +}
diff --git a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs index 3007c9a..24cde94 100644 --- a/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs +++ b/nearby/connections/ukey2/ukey2_connections/fuzz/fuzz_targets/fuzz_handshake.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,55 +13,54 @@ // See the License for the specific language governing permissions and // limitations under the License. -use arbitrary::Arbitrary; use crypto_provider_rustcrypto::RustCrypto; -use libfuzzer_sys::fuzz_target; +use derive_fuzztest::fuzztest; use rand_chacha::rand_core::SeedableRng; use ukey2_connections::HandshakeImplementation; use ukey2_connections::{ D2DHandshakeContext, InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, }; +use ukey2_rs::NextProtocol; -#[derive(Debug, Arbitrary)] -struct FuzzInput<'a> { +#[fuzztest] +fn test( client_rng_seed: [u8; 32], server_rng_seed: [u8; 32], - override_client_init: Option<&'a [u8]>, - override_server_init: Option<&'a [u8]>, - override_client_finish: Option<&'a [u8]>, -} - -fuzz_target!(|input: FuzzInput| { + override_client_init: Option<Vec<u8>>, + override_server_init: Option<Vec<u8>>, + override_client_finish: Option<Vec<u8>>, +) { let mut initiator_ctx = InitiatorD2DHandshakeContext::<RustCrypto, _>::new_impl( HandshakeImplementation::Spec, - rand_chacha::ChaChaRng::from_seed(input.client_rng_seed), + rand_chacha::ChaChaRng::from_seed(client_rng_seed), + vec![NextProtocol::Aes256CbcHmacSha256], ); let mut server_ctx = ServerD2DHandshakeContext::<RustCrypto, _>::new_impl( HandshakeImplementation::Spec, - rand_chacha::ChaChaRng::from_seed(input.server_rng_seed), + rand_chacha::ChaChaRng::from_seed(server_rng_seed), + &[NextProtocol::Aes256CbcHmacSha256], ); let client_init = initiator_ctx .get_next_handshake_message() .expect("Initial get_next_handshake_message should succeed"); - let client_init_with_override = input.override_client_init.unwrap_or(&client_init); + let client_init_with_override = override_client_init.unwrap_or(client_init); let _result = server_ctx - .handle_handshake_message(client_init_with_override) + .handle_handshake_message(&client_init_with_override) .and_then(|_| { let server_init = server_ctx.get_next_handshake_message().expect(concat!( "get_next_handshake_message should succeed when previous ", "handle_handshake_message succeeded" )); - let server_init_with_override = input.override_server_init.unwrap_or(&server_init); - initiator_ctx.handle_handshake_message(server_init_with_override) + let server_init_with_override = override_server_init.unwrap_or(server_init); + initiator_ctx.handle_handshake_message(&server_init_with_override) }) .and_then(|_| { let client_finish = initiator_ctx.get_next_handshake_message().expect(concat!( "get_next_handshake_message should succeed when previous ", "handle_handshake_message succeeded" )); - let client_finish_with_override = - input.override_client_finish.unwrap_or(&client_finish); - server_ctx.handle_handshake_message(client_finish_with_override) + let client_finish_with_override = override_client_finish.unwrap_or(client_finish); + server_ctx.handle_handshake_message(&client_finish_with_override) }) .map(|_| { assert!(server_ctx.is_handshake_complete()); @@ -71,4 +70,4 @@ } // Note: initiator keeps returning client_finish at the Complete state }); -}); +}
diff --git a/nearby/connections/ukey2/ukey2_connections/src/crypto_utils.rs b/nearby/connections/ukey2/ukey2_connections/src/crypto_utils.rs index f4bd671..815d3f0 100644 --- a/nearby/connections/ukey2/ukey2_connections/src/crypto_utils.rs +++ b/nearby/connections/ukey2/ukey2_connections/src/crypto_utils.rs
@@ -13,10 +13,11 @@ // limitations under the License. use crate::d2d_connection_context_v1::{Aes256Key as RawAes256Key, AesCbcIv}; +use crypto_provider::aead::AeadError; use crypto_provider::aes::cbc::DecryptionError; -/// Encrypt message of length N -pub(crate) fn encrypt< +/// Encrypt message of length N with AES-CBC-256 +pub(crate) fn encrypt_cbc< R: rand::Rng + rand::CryptoRng, A: crypto_provider::aes::cbc::AesCbcPkcs7Padded, >( @@ -29,10 +30,40 @@ (ciphertext, iv) } -pub(crate) fn decrypt<A: crypto_provider::aes::cbc::AesCbcPkcs7Padded>( +/// Decrypt message of length N with AES-CBC-256 +pub(crate) fn decrypt_cbc<A: crypto_provider::aes::cbc::AesCbcPkcs7Padded>( key: &RawAes256Key, ciphertext: &[u8], iv: &AesCbcIv, ) -> Result<Vec<u8>, DecryptionError> { A::decrypt(&key[..].try_into().unwrap(), iv, ciphertext) } + +// TODO: Implement caching of these ciphers per connection so we don't recreate on each computation. +pub(crate) fn encrypt_gcm_siv< + A: crypto_provider::aead::AesGcmSiv + + crypto_provider::aead::AeadInit<crypto_provider::aes::Aes256Key>, +>( + key: &RawAes256Key, + plaintext: &[u8], + aad: &[u8], + nonce: &A::Nonce, +) -> Result<Vec<u8>, AeadError> { + let converted_key = key.as_slice().try_into().unwrap(); + let encrypter = A::new(&converted_key); + encrypter.encrypt(plaintext, aad, nonce) +} + +pub(crate) fn decrypt_gcm_siv< + A: crypto_provider::aead::AesGcmSiv + + crypto_provider::aead::AeadInit<crypto_provider::aes::Aes256Key>, +>( + key: &RawAes256Key, + ciphertext: &[u8], + aad: &[u8], + nonce: &A::Nonce, +) -> Result<Vec<u8>, AeadError> { + let converted_key = key.as_slice().try_into().unwrap(); + let decrypter = A::new(&converted_key); + decrypter.decrypt(ciphertext, aad, nonce) +}
diff --git a/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs b/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs index 70a1556..22def10 100644 --- a/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs +++ b/nearby/connections/ukey2/ukey2_connections/src/d2d_connection_context_v1.rs
@@ -18,14 +18,15 @@ use bytes::BufMut; use rand::SeedableRng as _; +use crypto_provider::aead::Aead; use crypto_provider::{hkdf::Hkdf, hmac::Hmac, sha2::Sha256, CryptoProvider}; -use ukey2_proto::protobuf::Message as _; +use ukey2_proto::protobuf::{Enum, Message as _}; use ukey2_proto::ukey2_all_proto::{ device_to_device_messages::DeviceToDeviceMessage, securegcm::{GcmMetadata, Type}, securemessage::{EncScheme, Header, HeaderAndBody, SecureMessage, SigScheme}, }; -use ukey2_rs::CompletedHandshake; +use ukey2_rs::{CompletedHandshake, NextProtocol}; use crate::{crypto_utils, java_utils}; @@ -52,7 +53,7 @@ ]; pub(crate) type AesCbcIv = [u8; 16]; -pub type Aes256Key = [u8; 32]; +pub type Aes256Key = [u8; AES_256_KEY_SIZE]; const HKDF_INFO_KEY_INITIATOR: &[u8; 6] = b"client"; const HKDF_INFO_KEY_RESPONDER: &[u8; 6] = b"server"; @@ -118,6 +119,7 @@ signing_key: Aes256Key, verify_key: Aes256Key, rng: R, + protocol: NextProtocol, } /// Error type for [`decode_message_from_peer`][D2DConnectionContextV1::decode_message_from_peer]. @@ -160,14 +162,13 @@ where R: rand::Rng + rand::SeedableRng + rand::CryptoRng, { - pub(crate) const NEXT_PROTOCOL_IDENTIFIER: &'static str = "AES_256_CBC-HMAC_SHA256"; - pub fn new<C: CryptoProvider>( decode_sequence_num: i32, encode_sequence_num: i32, encode_key: Aes256Key, decode_key: Aes256Key, rng: R, + protocol: NextProtocol, ) -> Self { let encryption_key = derive_aes256_key::<C>(&encode_key, b"ENC:2"); let decryption_key = derive_aes256_key::<C>(&decode_key, b"ENC:2"); @@ -183,6 +184,7 @@ signing_key, verify_key, rng, + protocol, } } @@ -198,6 +200,7 @@ encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_INITIATOR).unwrap(), encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_RESPONDER).unwrap(), rng, + handshake.next_protocol, ) } @@ -213,6 +216,7 @@ encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_RESPONDER).unwrap(), encryption_key::<32, C>(&next_protocol_secret, HKDF_INFO_KEY_INITIATOR).unwrap(), rng, + handshake.next_protocol, ) } @@ -240,6 +244,9 @@ ret.put_i32(self.decode_sequence_num); ret.extend_from_slice(self.encode_key.as_slice()); ret.extend_from_slice(self.decode_key.as_slice()); + if self.protocol == NextProtocol::Aes256GcmSiv { + ret.extend_from_slice(&EncScheme::AES_256_GCM_SIV.value().to_be_bytes()) + } ret } @@ -247,31 +254,52 @@ session: &[u8], rng: R, ) -> Result<Self, DeserializeError> { - if session.len() != 73 { + if session.len() != 73 && session.len() != 77 { return Err(DeserializeError::BadDataLength); } let (rem, _) = nom::bytes::complete::tag(PROTOCOL_VERSION.to_be_bytes())(session) .map_err(|_: nom::Err<nom::error::Error<_>>| DeserializeError::BadProtocolVersion)?; - - let (_, (encode_sequence_num, decode_sequence_num, encode_key, decode_key)) = - nom::combinator::all_consuming(nom::sequence::tuple::<_, _, nom::error::Error<_>, _>( - ( - nom::number::complete::be_i32, - nom::number::complete::be_i32, - nom::combinator::map_res( - nom::bytes::complete::take(32_usize), - TryInto::<Aes256Key>::try_into, - ), - nom::combinator::map_res( - nom::bytes::complete::take(32_usize), - TryInto::<Aes256Key>::try_into, - ), + let ( + _, + (encode_sequence_num, decode_sequence_num, encode_key, decode_key, next_protocol_int), + ) = nom::combinator::all_consuming(nom::sequence::tuple::<_, _, nom::error::Error<_>, _>( + ( + nom::number::complete::be_i32, + nom::number::complete::be_i32, + nom::combinator::map_res( + nom::bytes::complete::take(32_usize), + TryInto::<Aes256Key>::try_into, ), - ))(rem) - // This should always succeed since all of the parsers above are valid over the entire - // [u8] space, and we already checked the length at the start. - .expect("Saved session parsing should succeed"); - Ok(Self::new::<C>(encode_sequence_num, decode_sequence_num, encode_key, decode_key, rng)) + nom::combinator::map_res( + nom::bytes::complete::take(32_usize), + TryInto::<Aes256Key>::try_into, + ), + nom::combinator::opt(nom::number::complete::be_i32), + ), + ))(rem) + // This should always succeed since all of the parsers above are valid over the entire + // [u8] space, and we already checked the length at the start. + .expect("Saved session parsing should succeed"); + + let next_protocol = if let Some(next_protocol_raw) = next_protocol_int { + let enc_scheme = + EncScheme::from_i32(next_protocol_raw).ok_or(DeserializeError::BadData)?; + match enc_scheme { + EncScheme::NONE => Err(DeserializeError::BadData), + EncScheme::AES_256_CBC => Ok(NextProtocol::Aes256CbcHmacSha256), + EncScheme::AES_256_GCM_SIV => Ok(NextProtocol::Aes256GcmSiv), + }? + } else { + NextProtocol::Aes256CbcHmacSha256 + }; + Ok(Self::new::<C>( + encode_sequence_num, + decode_sequence_num, + encode_key, + decode_key, + rng, + next_protocol, + )) } /// Once initiator and responder have exchanged public keys, use this method to encrypt and @@ -292,11 +320,6 @@ message: payload.to_vec(), sequence_num: self.get_sequence_number_for_encoding(), }); - let (ciphertext, iv) = crypto_utils::encrypt::<_, C::AesCbcPkcs7Padded>( - &self.encryption_key, - message.as_slice(), - &mut self.rng, - ); let metadata = GcmMetadata { type_: Some(Type::DEVICE_TO_DEVICE_MESSAGE.into()), // As specified in @@ -304,32 +327,74 @@ version: Some(1), ..Default::default() }; - let header = Header { - signature_scheme: Some(SigScheme::HMAC_SHA256.into()), - encryption_scheme: Some(EncScheme::AES_256_CBC.into()), - iv: Some(iv.to_vec()), - public_metadata: Some(metadata.write_to_bytes().unwrap()), - associated_data_length: associated_data.as_ref().map(|d| d.as_ref().len() as u32), - ..Default::default() + let (ciphertext, header) = match self.protocol { + NextProtocol::Aes256GcmSiv => { + let nonce: [u8; 12] = self.rng.gen(); + let ciphertext = crypto_utils::encrypt_gcm_siv::<C::Aes256GcmSiv>( + &self.encryption_key, + &message, + associated_data.as_ref().map_or(&[], AsRef::as_ref), + &nonce, + ) + .unwrap(); + ( + ciphertext, + Header { + signature_scheme: Some(SigScheme::AEAD.into()), + encryption_scheme: Some(EncScheme::AES_256_GCM_SIV.into()), + nonce: Some(nonce.to_vec()), + public_metadata: Some(metadata.write_to_bytes().unwrap()), + associated_data_length: associated_data + .as_ref() + .map(|d| d.as_ref().len() as u32), + ..Default::default() + }, + ) + } + NextProtocol::Aes256CbcHmacSha256 => { + let (ciphertext, iv) = crypto_utils::encrypt_cbc::<_, C::AesCbcPkcs7Padded>( + &self.encryption_key, + message.as_slice(), + &mut self.rng, + ); + ( + ciphertext, + Header { + signature_scheme: Some(SigScheme::HMAC_SHA256.into()), + encryption_scheme: Some(EncScheme::AES_256_CBC.into()), + iv: Some(iv.to_vec()), + public_metadata: Some(metadata.write_to_bytes().unwrap()), + associated_data_length: associated_data + .as_ref() + .map(|d| d.as_ref().len() as u32), + ..Default::default() + }, + ) + } }; + let header_and_body = HeaderAndBody { header: Some(header).into(), body: Some(ciphertext), ..Default::default() }; let header_and_body_bytes = header_and_body.write_to_bytes().unwrap(); - - // add sha256 MAC - let mut hmac = C::HmacSha256::new_from_slice(&self.signing_key).unwrap(); - hmac.update(header_and_body_bytes.as_slice()); - if let Some(associated_data_vec) = associated_data.as_ref() { - hmac.update(associated_data_vec.as_ref()) - } - let result_mac = hmac.finalize().to_vec(); + let signature = match self.protocol { + NextProtocol::Aes256CbcHmacSha256 => { + // add sha256 MAC + let mut hmac = C::HmacSha256::new_from_slice(&self.signing_key).unwrap(); + hmac.update(header_and_body_bytes.as_slice()); + if let Some(associated_data_vec) = associated_data.as_ref() { + hmac.update(associated_data_vec.as_ref()) + } + Some(hmac.finalize().to_vec()) + } + NextProtocol::Aes256GcmSiv => Some(vec![]), + }; let secure_message = SecureMessage { header_and_body: Some(header_and_body_bytes), - signature: Some(result_mac), + signature, ..Default::default() }; secure_message.write_to_bytes().unwrap() @@ -349,36 +414,60 @@ ) -> Result<Vec<u8>, DecodeError> { // first confirm that the payload MAC matches the header_and_body let message = SecureMessage::parse_from_bytes(payload).map_err(|_| DecodeError::BadData)?; - let payload_mac: [u8; 32] = message - .signature - .and_then(|signature| signature.try_into().ok()) - .ok_or(DecodeError::BadData)?; - let payload = message.header_and_body.ok_or(DecodeError::BadData)?; - let mut hmac = C::HmacSha256::new_from_slice(&self.verify_key).unwrap(); - hmac.update(&payload); - if let Some(associated_data) = associated_data.as_ref() { - hmac.update(associated_data.as_ref()) + let header_and_body = message.header_and_body.ok_or(DecodeError::BadData)?; + match self.protocol { + NextProtocol::Aes256CbcHmacSha256 => { + let payload_mac: [u8; 32] = message + .signature + .and_then(|signature| signature.try_into().ok()) + .ok_or(DecodeError::BadData)?; + let mut hmac = C::HmacSha256::new_from_slice(&self.verify_key).unwrap(); + hmac.update(&header_and_body); + if let Some(associated_data) = associated_data.as_ref() { + hmac.update(associated_data.as_ref()) + } + hmac.verify(payload_mac).map_err(|_| DecodeError::BadData)?; + } + NextProtocol::Aes256GcmSiv => {} // No need to check signature on an AEAD cipher. } - hmac.verify(payload_mac).map_err(|_| DecodeError::BadData)?; + let payload = - HeaderAndBody::parse_from_bytes(&payload).map_err(|_| DecodeError::BadData)?; - let associated_data_len = - payload.header.as_ref().and_then(|header| header.associated_data_length); - if associated_data_len != associated_data.map(|ad| ad.as_ref().len() as u32) { - return Err(DecodeError::BadData); - } - let iv: AesCbcIv = payload - .header - .as_ref() - .and_then(|header| header.iv().try_into().ok()) - .ok_or(DecodeError::BadData)?; - let decrypted = crypto_utils::decrypt::<C::AesCbcPkcs7Padded>( - &self.decryption_key, - &payload.body.unwrap_or_default(), - &iv, - ) - .map_err(|_| DecodeError::BadData)?; - let d2d_message = unwrap_device_to_device_message(decrypted.as_slice())?; + HeaderAndBody::parse_from_bytes(&header_and_body).map_err(|_| DecodeError::BadData)?; + let decrypted = match self.protocol { + NextProtocol::Aes256GcmSiv => { + let nonce: <<C as CryptoProvider>::Aes256GcmSiv as Aead>::Nonce = payload + .header + .as_ref() + .and_then(|header| header.nonce().try_into().ok()) + .ok_or(DecodeError::BadData)?; + crypto_utils::decrypt_gcm_siv::<C::Aes256GcmSiv>( + &self.decryption_key, + &payload.body.unwrap_or_default(), + associated_data.as_ref().map_or(&[], AsRef::as_ref), + &nonce, + ) + .map_err(|_| DecodeError::BadData)? + } + NextProtocol::Aes256CbcHmacSha256 => { + let associated_data_len = + payload.header.as_ref().and_then(|header| header.associated_data_length); + if associated_data_len != associated_data.map(|ad| ad.as_ref().len() as u32) { + return Err(DecodeError::BadData); + } + let iv: AesCbcIv = payload + .header + .as_ref() + .and_then(|header| header.iv().try_into().ok()) + .ok_or(DecodeError::BadData)?; + crypto_utils::decrypt_cbc::<C::AesCbcPkcs7Padded>( + &self.decryption_key, + &payload.body.unwrap_or_default(), + &iv, + ) + .map_err(|_| DecodeError::BadData)? + } + }; + let d2d_message = unwrap_device_to_device_message(&decrypted)?; if d2d_message.sequence_num != self.get_sequence_number_for_decoding() + 1 { return Err(DecodeError::BadSequenceNumber); }
diff --git a/nearby/connections/ukey2/ukey2_connections/src/d2d_handshake_context.rs b/nearby/connections/ukey2/ukey2_connections/src/d2d_handshake_context.rs index d9e1524..5e7262b 100644 --- a/nearby/connections/ukey2/ukey2_connections/src/d2d_handshake_context.rs +++ b/nearby/connections/ukey2/ukey2_connections/src/d2d_handshake_context.rs
@@ -15,11 +15,11 @@ use crate::d2d_connection_context_v1::D2DConnectionContextV1; use crypto_provider::CryptoProvider; -use rand::{rngs::StdRng, SeedableRng as _}; +use rand::SeedableRng as _; use std::{collections::HashSet, mem}; use ukey2_rs::{ - CompletedHandshake, HandshakeImplementation, StateMachine, Ukey2Client, Ukey2ClientStage1, - Ukey2Server, Ukey2ServerStage1, Ukey2ServerStage2, + CompletedHandshake, HandshakeImplementation, NextProtocol, StateMachine, Ukey2Client, + Ukey2ClientStage1, Ukey2Server, Ukey2ServerStage1, Ukey2ServerStage2, }; #[derive(Debug)] @@ -99,8 +99,8 @@ } impl<C: CryptoProvider> InitiatorD2DHandshakeContext<C, rand::rngs::StdRng> { - pub fn new(handshake_impl: HandshakeImplementation) -> Self { - Self::new_impl(handshake_impl, rand::rngs::StdRng::from_entropy()) + pub fn new(handshake_impl: HandshakeImplementation, next_protocols: Vec<NextProtocol>) -> Self { + Self::new_impl(handshake_impl, rand::rngs::StdRng::from_entropy(), next_protocols) } } @@ -110,12 +110,12 @@ { // Used for testing / fuzzing only. #[doc(hidden)] - pub fn new_impl(handshake_impl: HandshakeImplementation, mut rng: R) -> Self { - let client = Ukey2ClientStage1::from( - &mut rng, - D2DConnectionContextV1::<StdRng>::NEXT_PROTOCOL_IDENTIFIER.to_owned(), - handshake_impl, - ); + pub fn new_impl( + handshake_impl: HandshakeImplementation, + mut rng: R, + next_protocols: Vec<NextProtocol>, + ) -> Self { + let client = Ukey2ClientStage1::from(&mut rng, next_protocols, handshake_impl); Self { state: InitiatorState::Stage1(client), rng } } } @@ -157,6 +157,14 @@ } } + fn to_connection_context(&mut self) -> Result<D2DConnectionContextV1<R>, HandshakeError> { + // Since self.rng is expected to be a seeded PRNG, not an OsRng directly, from_rng + // should never fail. https://rust-random.github.io/book/guide-err.html + let rng = R::from_rng(&mut self.rng).unwrap(); + self.to_completed_handshake() + .map(|h| D2DConnectionContextV1::from_initiator_handshake::<C>(h, rng)) + } + fn to_completed_handshake(&self) -> Result<&CompletedHandshake, HandshakeError> { match &self.state { InitiatorState::Stage1(_) | InitiatorState::Invalid => { @@ -165,18 +173,6 @@ InitiatorState::Complete(c) => Ok(c.completed_handshake()), } } - - fn to_connection_context(&mut self) -> Result<D2DConnectionContextV1<R>, HandshakeError> { - // Since self.rng is expected to be a seeded PRNG, not an OsRng directly, from_rng - // should never fail. https://rust-random.github.io/book/guide-err.html - let rng = R::from_rng(&mut self.rng).unwrap(); - self.to_completed_handshake().and_then(|h| match h.next_protocol.as_ref() { - D2DConnectionContextV1::<R>::NEXT_PROTOCOL_IDENTIFIER => { - Ok(D2DConnectionContextV1::from_initiator_handshake::<C>(h, rng)) - } - _ => Err(HandshakeError::HandshakeNotComplete), - }) - } } enum ServerState<C: CryptoProvider> { @@ -198,8 +194,8 @@ } impl<C: CryptoProvider> ServerD2DHandshakeContext<C, rand::rngs::StdRng> { - pub fn new(handshake_impl: HandshakeImplementation) -> Self { - Self::new_impl(handshake_impl, rand::rngs::StdRng::from_entropy()) + pub fn new(handshake_impl: HandshakeImplementation, next_protocols: &[NextProtocol]) -> Self { + Self::new_impl(handshake_impl, rand::rngs::StdRng::from_entropy(), next_protocols) } } @@ -209,13 +205,14 @@ { // Used for testing / fuzzing only. #[doc(hidden)] - pub fn new_impl(handshake_impl: HandshakeImplementation, rng: R) -> Self { + pub fn new_impl( + handshake_impl: HandshakeImplementation, + rng: R, + next_protocols: &[NextProtocol], + ) -> Self { Self { state: ServerState::Stage1(Ukey2ServerStage1::from( - HashSet::from([ - D2DConnectionContextV1::<rand::rngs::StdRng>::NEXT_PROTOCOL_IDENTIFIER - .to_owned(), - ]), + HashSet::from_iter(next_protocols.iter().map(|np| np.to_string())), handshake_impl, )), rng, @@ -280,16 +277,7 @@ // Since self.rng is expected to be a seeded PRNG, not an OsRng directly, from_rng // should never fail. https://rust-random.github.io/book/guide-err.html let rng = R::from_rng(&mut self.rng).unwrap(); - self.to_completed_handshake().map(|h| match h.next_protocol.as_ref() { - D2DConnectionContextV1::<R>::NEXT_PROTOCOL_IDENTIFIER => { - D2DConnectionContextV1::from_responder_handshake::<C>(h, rng) - } - _ => { - // This should never happen because ukey2_handshake should set next_protocol to - // one of the values we passed in Ukey2ServerStage1::from, which doesn't contain - // any other value. - panic!("Unknown next protocol: {}", h.next_protocol); - } - }) + self.to_completed_handshake() + .map(|h| D2DConnectionContextV1::from_responder_handshake::<C>(h, rng)) } }
diff --git a/nearby/connections/ukey2/ukey2_connections/src/lib.rs b/nearby/connections/ukey2/ukey2_connections/src/lib.rs index b3ed937..eb8a55b 100644 --- a/nearby/connections/ukey2/ukey2_connections/src/lib.rs +++ b/nearby/connections/ukey2/ukey2_connections/src/lib.rs
@@ -42,4 +42,4 @@ D2DHandshakeContext, HandleMessageError, HandshakeError, InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, }; -pub use ukey2_rs::HandshakeImplementation; +pub use ukey2_rs::{HandshakeImplementation, NextProtocol};
diff --git a/nearby/connections/ukey2/ukey2_connections/src/tests.rs b/nearby/connections/ukey2/ukey2_connections/src/tests.rs index d6acecc..9f0b13e 100644 --- a/nearby/connections/ukey2/ukey2_connections/src/tests.rs +++ b/nearby/connections/ukey2/ukey2_connections/src/tests.rs
@@ -18,10 +18,10 @@ use crypto_provider_default::CryptoProviderImpl; use rand::SeedableRng; use rand::{rngs::StdRng, CryptoRng, RngCore}; -use ukey2_rs::HandshakeImplementation; +use ukey2_rs::{HandshakeImplementation, NextProtocol}; use crate::{ - crypto_utils::{decrypt, encrypt}, + crypto_utils::{decrypt_cbc, encrypt_cbc}, java_utils, Aes256Key, D2DConnectionContextV1, D2DHandshakeContext, DeserializeError, InitiatorD2DHandshakeContext, ServerD2DHandshakeContext, }; @@ -33,8 +33,8 @@ let message = b"Hello World!"; let key = b"42424242424242424242424242424242"; let (ciphertext, iv) = - encrypt::<_, AesCbcPkcs7Padded>(key, message, &mut rand::rngs::StdRng::from_entropy()); - let decrypt_result = decrypt::<AesCbcPkcs7Padded>(key, ciphertext.as_slice(), &iv); + encrypt_cbc::<_, AesCbcPkcs7Padded>(key, message, &mut rand::rngs::StdRng::from_entropy()); + let decrypt_result = decrypt_cbc::<AesCbcPkcs7Padded>(key, ciphertext.as_slice(), &iv); let ptext = decrypt_result.expect("Decrypt should be successful"); assert_eq!(ptext, message.to_vec()); } @@ -44,7 +44,7 @@ let message = b"Hello World!"; let key = b"42424242424242424242424242424242"; let mut rng = MockRng; - let (ciphertext, iv) = encrypt::<_, AesCbcPkcs7Padded>(key, message, &mut rng); + let (ciphertext, iv) = encrypt_cbc::<_, AesCbcPkcs7Padded>(key, message, &mut rng); // Expected values extracted from the results of the current implementation. // This test makes sure that we don't accidentally change the encryption logic that // causes incompatibility between versions. @@ -60,7 +60,7 @@ let iv = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; let ciphertext = [20, 59, 195, 101, 11, 208, 245, 128, 247, 196, 81, 80, 158, 77, 174, 61]; let key = b"42424242424242424242424242424242"; - let plaintext = decrypt::<AesCbcPkcs7Padded>(key, &ciphertext, &iv).unwrap(); + let plaintext = decrypt_cbc::<AesCbcPkcs7Padded>(key, &ciphertext, &iv).unwrap(); assert_eq!(plaintext, b"Hello World!"); } @@ -68,27 +68,41 @@ fn decrypt_test_wrong_key() { let message = b"Hello World!"; let good_key = b"42424242424242424242424242424242"; - let (ciphertext, iv) = - encrypt::<_, AesCbcPkcs7Padded>(good_key, message, &mut rand::rngs::StdRng::from_entropy()); + let (ciphertext, iv) = encrypt_cbc::<_, AesCbcPkcs7Padded>( + good_key, + message, + &mut rand::rngs::StdRng::from_entropy(), + ); let bad_key = b"43434343434343434343434343434343"; - let decrypt_result = decrypt::<AesCbcPkcs7Padded>(bad_key, ciphertext.as_slice(), &iv); + let decrypt_result = decrypt_cbc::<AesCbcPkcs7Padded>(bad_key, ciphertext.as_slice(), &iv); match decrypt_result { // The padding is valid, but the decrypted value should be bad since the keys don't match Ok(decrypted_bad) => assert_ne!(decrypted_bad, message), // The padding is bad, so it returns an error and is unable to decrypt Err(crypto_provider::aes::cbc::DecryptionError::BadPadding) => (), } - let decrypt_result = decrypt::<AesCbcPkcs7Padded>(good_key, ciphertext.as_slice(), &iv); + let decrypt_result = decrypt_cbc::<AesCbcPkcs7Padded>(good_key, ciphertext.as_slice(), &iv); let ptext = decrypt_result.unwrap(); assert_eq!(ptext, message.to_vec()); } -fn run_handshake() -> (D2DConnectionContextV1, D2DConnectionContextV1) { - run_handshake_with_rng::<CryptoProviderImpl, _>(rand::rngs::StdRng::from_entropy()) +fn run_cbc_handshake() -> (D2DConnectionContextV1, D2DConnectionContextV1) { + run_handshake_with_rng::<CryptoProviderImpl, _>( + rand::rngs::StdRng::from_entropy(), + vec![NextProtocol::Aes256CbcHmacSha256], + ) +} + +fn run_gcm_handshake() -> (D2DConnectionContextV1, D2DConnectionContextV1) { + run_handshake_with_rng::<CryptoProviderImpl, _>( + rand::rngs::StdRng::from_entropy(), + vec![NextProtocol::Aes256GcmSiv], + ) } fn run_handshake_with_rng<C, R>( mut rng: R, + next_protocols: Vec<NextProtocol>, ) -> (D2DConnectionContextV1<R>, D2DConnectionContextV1<R>) where C: CryptoProvider, @@ -97,10 +111,12 @@ let mut initiator_ctx = InitiatorD2DHandshakeContext::<C, R>::new_impl( HandshakeImplementation::Spec, R::from_rng(&mut rng).unwrap(), + next_protocols.clone(), ); let mut server_ctx = ServerD2DHandshakeContext::<C, R>::new_impl( HandshakeImplementation::Spec, R::from_rng(&mut rng).unwrap(), + &next_protocols, ); server_ctx .handle_handshake_message( @@ -130,7 +146,10 @@ let rng = MockRng; let message = b"Hello World!"; let (mut init_conn_ctx, mut server_conn_ctx) = - run_handshake_with_rng::<RustCryptoImpl<MockRng>, _>(rng); + run_handshake_with_rng::<RustCryptoImpl<MockRng>, _>( + rng, + vec![NextProtocol::Aes256CbcHmacSha256], + ); let encoded = init_conn_ctx.encode_message_to_peer::<RustCryptoImpl<MockRng>, &[u8]>(message, None); // Expected values extracted from the results of the current implementation. @@ -140,10 +159,10 @@ encoded, &[ 10, 64, 10, 28, 8, 1, 16, 2, 42, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 50, 4, 8, 13, 16, 1, 18, 32, 58, 224, 12, 10, 216, 38, 219, 232, 231, 222, 226, 63, 37, - 20, 92, 208, 40, 8, 29, 98, 226, 132, 30, 61, 229, 78, 20, 182, 217, 26, 176, 77, 18, - 32, 212, 221, 67, 39, 137, 138, 163, 222, 119, 216, 28, 176, 130, 152, 211, 63, 182, - 45, 239, 234, 248, 148, 9, 150, 204, 117, 32, 216, 5, 126, 224, 39 + 50, 4, 8, 13, 16, 1, 18, 32, 23, 58, 102, 24, 40, 222, 59, 212, 182, 181, 96, 44, 57, + 21, 93, 253, 71, 54, 67, 37, 226, 43, 104, 224, 178, 221, 219, 189, 106, 135, 175, 150, + 18, 32, 134, 9, 237, 41, 112, 183, 129, 198, 240, 13, 139, 66, 21, 56, 28, 100, 142, + 240, 155, 52, 242, 11, 211, 132, 175, 230, 15, 241, 208, 185, 15, 105 ] ); let decoded = server_conn_ctx @@ -155,7 +174,17 @@ #[test] fn send_receive_message() { let message = b"Hello World!"; - let (mut init_conn_ctx, mut server_conn_ctx) = run_handshake(); + let (mut init_conn_ctx, mut server_conn_ctx) = run_cbc_handshake(); + let encoded = init_conn_ctx.encode_message_to_peer::<CryptoProviderImpl, &[u8]>(message, None); + let decoded = server_conn_ctx + .decode_message_from_peer::<CryptoProviderImpl, &[u8]>(encoded.as_slice(), None); + assert_eq!(message.to_vec(), decoded.expect("Decode should be successful")); +} + +#[test] +fn send_receive_message_gcm() { + let message = b"Hello World!"; + let (mut init_conn_ctx, mut server_conn_ctx) = run_gcm_handshake(); let encoded = init_conn_ctx.encode_message_to_peer::<CryptoProviderImpl, &[u8]>(message, None); let decoded = server_conn_ctx .decode_message_from_peer::<CryptoProviderImpl, &[u8]>(encoded.as_slice(), None); @@ -165,7 +194,7 @@ #[test] fn send_receive_message_associated_data() { let message = b"Hello World!"; - let (mut init_conn_ctx, mut server_conn_ctx) = run_handshake(); + let (mut init_conn_ctx, mut server_conn_ctx) = run_cbc_handshake(); let encoded = init_conn_ctx .encode_message_to_peer::<CryptoProviderImpl, _>(message, Some(b"associated data")); let decoded = server_conn_ctx.decode_message_from_peer::<CryptoProviderImpl, _>( @@ -187,7 +216,7 @@ #[test] fn test_save_restore_session() { - let (init_conn_ctx, server_conn_ctx) = run_handshake(); + let (init_conn_ctx, server_conn_ctx) = run_cbc_handshake(); let init_session = init_conn_ctx.save_session(); let server_session = server_conn_ctx.save_session(); let mut init_restored_ctx = @@ -206,7 +235,7 @@ #[test] fn test_save_restore_bad_session() { - let (init_conn_ctx, server_conn_ctx) = run_handshake(); + let (init_conn_ctx, server_conn_ctx) = run_cbc_handshake(); let init_session = init_conn_ctx.save_session(); let server_session = server_conn_ctx.save_session(); let _ = @@ -219,7 +248,7 @@ #[test] fn test_save_restore_bad_protocol_version() { - let (init_conn_ctx, server_conn_ctx) = run_handshake(); + let (init_conn_ctx, server_conn_ctx) = run_cbc_handshake(); let init_session = init_conn_ctx.save_session(); let mut server_session = server_conn_ctx.save_session(); let _ = @@ -233,7 +262,7 @@ #[test] fn test_unique_session() { - let (mut init_conn_ctx, mut server_conn_ctx) = run_handshake(); + let (mut init_conn_ctx, mut server_conn_ctx) = run_cbc_handshake(); let init_session = init_conn_ctx.get_session_unique::<CryptoProviderImpl>(); let server_session = server_conn_ctx.get_session_unique::<CryptoProviderImpl>(); let message = b"Hello World!"; @@ -249,6 +278,7 @@ Aes256Key::default(), Aes256Key::default(), StdRng::from_entropy(), + NextProtocol::Aes256CbcHmacSha256, ); assert_eq!(init_session, init_session_after); assert_eq!(server_session, server_session_after);
diff --git a/nearby/connections/ukey2/ukey2_jni/Cargo.toml b/nearby/connections/ukey2/ukey2_jni/Cargo.toml index 8a5b0fe..bd615f5 100644 --- a/nearby/connections/ukey2/ukey2_jni/Cargo.toml +++ b/nearby/connections/ukey2/ukey2_jni/Cargo.toml
@@ -11,7 +11,6 @@ [dependencies] ukey2_connections = { path = "../ukey2_connections" } -ukey2_rs = { path = "../ukey2" } lock_adapter = {workspace = true, features = ["spin"]} cfg-if.workspace = true
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java b/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java index fcc07b8..537280a 100644 --- a/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java +++ b/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java
@@ -16,6 +16,7 @@ package com.google.security.cryptauth.lib.securegcm.ukey2; +import com.google.security.cryptauth.lib.securegcm.ukey2.D2DHandshakeContext.NextProtocol; import com.google.security.cryptauth.lib.securegcm.ukey2.D2DHandshakeContext.Role; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -43,15 +44,19 @@ D2DConnectionContextV1 connContext; D2DConnectionContextV1 serverConnContext; - @Param({"10", "1024"}) + @Param({"10", "512", "1024"}) int sizeKibs; + @Param NextProtocol nextProtocol; + byte[] inputBytes; @Setup public void setup() throws Exception { - D2DHandshakeContext initiatorContext = new D2DHandshakeContext(Role.INITIATOR); - D2DHandshakeContext serverContext = new D2DHandshakeContext(Role.RESPONDER); + D2DHandshakeContext initiatorContext = + new D2DHandshakeContext(Role.INITIATOR, new NextProtocol[] {nextProtocol}); + D2DHandshakeContext serverContext = + new D2DHandshakeContext(Role.RESPONDER, new NextProtocol[] {nextProtocol}); serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage()); initiatorContext.parseHandshakeMessage(serverContext.getNextHandshakeMessage()); serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage());
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java index 0e1ad62..a2db5ee 100644 --- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java +++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java
@@ -28,11 +28,16 @@ RESPONDER, } + public enum NextProtocol { + AES_256_GCM_SIV, + AES_256_CBC_HMAC_SHA256, + } + private final long contextPtr; private static native boolean is_handshake_complete(long contextPtr) throws BadHandleException; - private static native long create_context(boolean isClient); + private static native long create_context(boolean isClient, int[] supported_next_protocols); private static native byte[] get_next_handshake_message(long contextPtr) throws BadHandleException; @@ -45,8 +50,21 @@ private static native long to_connection_context(long contextPtr) throws HandshakeException; - public D2DHandshakeContext(@Nonnull Role role) { - this.contextPtr = create_context(role == Role.INITIATOR); + public D2DHandshakeContext(@Nonnull Role role) throws HandshakeException { + this(role, new NextProtocol[] {NextProtocol.AES_256_CBC_HMAC_SHA256}); + } + + public D2DHandshakeContext(@Nonnull Role role, @Nonnull NextProtocol[] nextProtocols) + throws HandshakeException { + if (nextProtocols.length < 1) { + throw new HandshakeException("Need more than one supported next protocol!"); + } + int[] nextProtocolCodes = new int[nextProtocols.length]; + for (int i = 0; i < nextProtocols.length; i++) { + nextProtocolCodes[i] = nextProtocols[i].ordinal(); + } + + this.contextPtr = create_context(role == Role.INITIATOR, nextProtocolCodes); } /** @@ -54,20 +72,42 @@ * * @return a D2DHandshakeContext for the role of initiator in the handshake. */ - public static D2DHandshakeContext forInitiator() { + public static D2DHandshakeContext forInitiator() throws HandshakeException { return new D2DHandshakeContext(Role.INITIATOR); } /** * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role. * + * @param nextProtocols Specification for the supported next protocols for this initiator. + * @return a D2DHandshakeContext for the role of initiator in the handshake. + */ + public static D2DHandshakeContext forInitiator(NextProtocol[] nextProtocols) + throws HandshakeException { + return new D2DHandshakeContext(Role.INITIATOR, nextProtocols); + } + + /** + * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role. + * * @return a D2DHandshakeContext for the role of responder/server in the handshake. */ - public static D2DHandshakeContext forResponder() { + public static D2DHandshakeContext forResponder() throws HandshakeException { return new D2DHandshakeContext(Role.RESPONDER); } /** + * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role. + * + * @param nextProtocols Specification for the supported next protocols for this responder. + * @return a D2DHandshakeContext for the role of responder/server in the handshake. + */ + public static D2DHandshakeContext forResponder(NextProtocol[] nextProtocols) + throws HandshakeException { + return new D2DHandshakeContext(Role.RESPONDER, nextProtocols); + } + + /** * Function that checks if the handshake is completed. * * @return true/false depending on if the handshake is complete.
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt b/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt index 2940652..ba3811c 100644 --- a/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt +++ b/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt
@@ -167,9 +167,71 @@ @Test fun throwsAlertExceptionWhenBadMessage() { val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER) - val exception = assertThrows<AlertException> { - serverContext.parseHandshakeMessage("Hello UKEY2".toByteArray()) - } + val exception = + assertThrows<AlertException> { + serverContext.parseHandshakeMessage("Hello UKEY2".toByteArray()) + } assert(exception.alertMessageToSend.isNotEmpty()) } + + @Test + fun testGcm() { + val initiatorContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.INITIATOR, + arrayOf(D2DHandshakeContext.NextProtocol.AES_256_GCM_SIV)) + val serverContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.RESPONDER, + arrayOf(D2DHandshakeContext.NextProtocol.AES_256_GCM_SIV)) + assertDoesNotThrow { + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage) + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + } + assert(serverContext.isHandshakeComplete) + assert(initiatorContext.isHandshakeComplete) + } + + @Test + fun testGcmServer_cbcClient() { + val initiatorContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.INITIATOR, + arrayOf(D2DHandshakeContext.NextProtocol.AES_256_CBC_HMAC_SHA256)) + val serverContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.RESPONDER, + arrayOf( + D2DHandshakeContext.NextProtocol.AES_256_CBC_HMAC_SHA256, + D2DHandshakeContext.NextProtocol.AES_256_GCM_SIV)) + assertDoesNotThrow { + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage) + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + } + assert(serverContext.isHandshakeComplete) + assert(initiatorContext.isHandshakeComplete) + } + + @Test + fun testGcmClient_cbcServer() { + val initiatorContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.INITIATOR, + arrayOf( + D2DHandshakeContext.NextProtocol.AES_256_CBC_HMAC_SHA256, + D2DHandshakeContext.NextProtocol.AES_256_GCM_SIV)) + val serverContext = + D2DHandshakeContext( + D2DHandshakeContext.Role.RESPONDER, + arrayOf(D2DHandshakeContext.NextProtocol.AES_256_CBC_HMAC_SHA256)) + assertDoesNotThrow { + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage) + serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage) + } + assert(serverContext.isHandshakeComplete) + assert(initiatorContext.isHandshakeComplete) + } }
diff --git a/nearby/connections/ukey2/ukey2_jni/src/lib.rs b/nearby/connections/ukey2/ukey2_jni/src/lib.rs index 2b277aa..e10f723 100644 --- a/nearby/connections/ukey2/ukey2_jni/src/lib.rs +++ b/nearby/connections/ukey2/ukey2_jni/src/lib.rs
@@ -18,25 +18,24 @@ //TODO: remove this and fix instances of unwrap/panic #![allow(clippy::unwrap_used, clippy::panic)] -use std::collections::HashMap; - -use jni::objects::{JByteArray, JClass, JThrowable}; -use jni::sys::{jboolean, jbyteArray, jint, jlong, JNI_TRUE}; +use jni::objects::{JByteArray, JClass, JIntArray, JThrowable}; +use jni::sys::{jboolean, jbyteArray, jint, jintArray, jlong, JNI_TRUE}; use jni::JNIEnv; use lazy_static::lazy_static; use lock_adapter::NoPoisonMutex; use rand::Rng; use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaCha20Rng; +use std::collections::HashMap; #[cfg(not(feature = "std"))] use lock_adapter::spin::Mutex; #[cfg(feature = "std")] -use lock_adapter::std::Mutex; +use lock_adapter::stdlib::Mutex; use ukey2_connections::{ D2DConnectionContextV1, D2DHandshakeContext, DecodeError, DeserializeError, HandleMessageError, - HandshakeError, HandshakeImplementation, InitiatorD2DHandshakeContext, + HandshakeError, HandshakeImplementation, InitiatorD2DHandshakeContext, NextProtocol, ServerD2DHandshakeContext, }; @@ -110,20 +109,57 @@ } /// Creates a new handshake context +// Safety: +// - Valid pointer: We know the message pointer is safe as it is coming directly from the JVM. +// - This pointer is nullable, but we null-check and default to AES-CBC-256_HMAC-SHA256 otherwise. +// - Lifetime - the jintArray passed in here is consumed immediately and is copied into a Rust array, +// so this data does not outlive this frame. +// - Aliasing - there is no other JObject representing this as it is only used in one place. +#[allow(clippy::not_unsafe_ptr_arg_deref)] #[no_mangle] pub extern "system" fn Java_com_google_security_cryptauth_lib_securegcm_ukey2_D2DHandshakeContext_create_1context( - _: JNIEnv, + mut env: JNIEnv, _: JClass, is_client: jboolean, + next_protocols: jintArray, ) -> jlong { + let next_protocols = if next_protocols.is_null() { + vec![NextProtocol::Aes256CbcHmacSha256] + } else { + let next_protocols_raw = unsafe { JIntArray::from_raw(next_protocols) }; + let next_protocols_len = + env.get_array_length(&next_protocols_raw).expect("Array should be valid!"); + let mut next_protocol_buf = + vec![0; usize::try_from(next_protocols_len).expect("len should be valid usize!")]; + env.get_int_array_region(&next_protocols_raw, 0, &mut next_protocol_buf) + .expect("Should've extracted next protocols!"); + next_protocol_buf + .iter() + .map(|p| match *p { + 0 => NextProtocol::Aes256CbcHmacSha256, + 1 => NextProtocol::Aes256GcmSiv, + _ => { + env.throw_new( + "com/google/security/cryptauth/lib/securegcm/ukey2/HandshakeException", + "Unsupported next protocols selected! Supported: [0, 1]", + ) + .expect("failed to find error class"); + unreachable!() + } + }) + .collect() + }; + if is_client == JNI_TRUE { let client_obj = Box::new(InitiatorD2DHandshakeContext::<CryptoProvider>::new( HandshakeImplementation::PublicKeyInProtobuf, + next_protocols, )); insert_handshake_handle(client_obj) as jlong } else { let server_obj = Box::new(ServerD2DHandshakeContext::<CryptoProvider>::new( HandshakeImplementation::PublicKeyInProtobuf, + &next_protocols, )); insert_handshake_handle(server_obj) as jlong }
diff --git a/nearby/connections/ukey2/ukey2_proto/proto/securegcm.proto b/nearby/connections/ukey2/ukey2_proto/proto/securegcm.proto index 40ac604..d5f2b14 100644 --- a/nearby/connections/ukey2/ukey2_proto/proto/securegcm.proto +++ b/nearby/connections/ukey2/ukey2_proto/proto/securegcm.proto
@@ -21,216 +21,6 @@ option java_outer_classname = "SecureGcmProto"; option objc_class_prefix = "SGCM"; -// Message used only during enrollment -// Field numbers should be kept in sync with DeviceInfo in: -// java/com/google/security/cryptauth/backend/services/common/common.proto -message GcmDeviceInfo { - // This field's name does not match the one in DeviceInfo for legacy reasons. - // Consider using long_device_id and device_type instead when enrolling - // non-android devices. - optional fixed64 android_device_id = 1; - - // Used for device_address of DeviceInfo field 2, but for GCM capable devices. - optional bytes gcm_registration_id = 102; - - // Used for device_address of DeviceInfo field 2, but for iOS devices. - optional bytes apn_registration_id = 202; - - // Does the user have notifications enabled for the given device address. - optional bool notification_enabled = 203 [default = true]; - - // Used for device_address of DeviceInfo field 2, a Bluetooth Mac address for - // the device (e.g., to be used with EasyUnlock) - optional string bluetooth_mac_address = 302; - - // SHA-256 hash of the device master key (from the key exchange). - // Differs from DeviceInfo field 3, which contains the actual master key. - optional bytes device_master_key_hash = 103; - - // A SecureMessage.EcP256PublicKey - required bytes user_public_key = 4; - - // device's model name - // (e.g., an android.os.Build.MODEL or UIDevice.model) - optional string device_model = 7; - - // device's locale - optional string locale = 8; - - // The handle for user_public_key (and implicitly, a master key) - optional bytes key_handle = 9; - - // The initial counter value for the device, sent by the device - optional int64 counter = 12 [default = 0]; - - // The Operating System version on the device - // (e.g., an android.os.Build.DISPLAY or UIDevice.systemVersion) - optional string device_os_version = 13; - - // The Operating System version number on the device - // (e.g., an android.os.Build.VERSION.SDK_INT) - optional int64 device_os_version_code = 14; - - // The Operating System release on the device - // (e.g., an android.os.Build.VERSION.RELEASE) - optional string device_os_release = 15; - - // The Operating System codename on the device - // (e.g., an android.os.Build.VERSION.CODENAME or UIDevice.systemName) - optional string device_os_codename = 16; - - // The software version running on the device - // (e.g., Authenticator app version string) - optional string device_software_version = 17; - - // The software version number running on the device - // (e.g., Authenticator app version code) - optional int64 device_software_version_code = 18; - - // Software package information if applicable - // (e.g., com.google.android.apps.authenticator2) - optional string device_software_package = 19; - - // Size of the display in thousandths of an inch (e.g., 7000 mils = 7 in) - optional int32 device_display_diagonal_mils = 22; - - // For Authzen capable devices, their Authzen protocol version - optional int32 device_authzen_version = 24; - - // Not all devices have device identifiers that fit in 64 bits. - optional bytes long_device_id = 29; - - // The device manufacturer name - // (e.g., android.os.Build.MANUFACTURER) - optional string device_manufacturer = 31; - - // Used to indicate which type of device this is. - optional DeviceType device_type = 32 [default = ANDROID]; - - // Fields corresponding to screenlock type/features and hardware features - // should be numbered in the 400 range. - - // Is this device using a secure screenlock (e.g., pattern or pin unlock) - optional bool using_secure_screenlock = 400 [default = false]; - - // Is auto-unlocking the screenlock (e.g., when at "home") supported? - optional bool auto_unlock_screenlock_supported = 401 [default = false]; - - // Is auto-unlocking the screenlock (e.g., when at "home") enabled? - optional bool auto_unlock_screenlock_enabled = 402 [default = false]; - - // Does the device have a Bluetooth (classic) radio? - optional bool bluetooth_radio_supported = 403 [default = false]; - - // Is the Bluetooth (classic) radio on? - optional bool bluetooth_radio_enabled = 404 [default = false]; - - // Does the device hardware support a mobile data connection? - optional bool mobile_data_supported = 405 [default = false]; - - // Does the device support tethering? - optional bool tethering_supported = 406 [default = false]; - - // Does the device have a BLE radio? - optional bool ble_radio_supported = 407 [default = false]; - - // Is the device a "Pixel Experience" Android device? - optional bool pixel_experience = 408 [default = false]; - - // Is the device running in the ARC++ container on a chromebook? - optional bool arc_plus_plus = 409 [default = false]; - - // Is the value set in |using_secure_screenlock| reliable? On some Android - // devices, the platform API to get the screenlock state is not trustworthy. - // See b/32212161. - optional bool is_screenlock_state_flaky = 410 [default = false]; - - // A list of multi-device software features supported by the device. - repeated SoftwareFeature supported_software_features = 411; - - // A list of multi-device software features currently enabled (active) on the - // device. - repeated SoftwareFeature enabled_software_features = 412; - - // The enrollment session id this is sent with - optional bytes enrollment_session_id = 1000; - - // A copy of the user's OAuth token - optional string oauth_token = 1001; -} - -// This enum is used by iOS devices as values for device_display_diagonal_mils -// in GcmDeviceInfo. There is no good way to calculate it on those devices. -enum AppleDeviceDiagonalMils { - // This is the mils diagonal on an iPhone 5. - APPLE_PHONE = 4000; - // This is the mils diagonal on an iPad mini. - APPLE_PAD = 7900; -} - -// This should be kept in sync with DeviceType in: -// java/com/google/security/cryptauth/backend/services/common/common_enums.proto -enum DeviceType { - UNKNOWN = 0; - ANDROID = 1; - CHROME = 2; - IOS = 3; - BROWSER = 4; - OSX = 5; -} - -// MultiDevice features which may be supported and enabled on a device. See -enum SoftwareFeature { - UNKNOWN_FEATURE = 0; - BETTER_TOGETHER_HOST = 1; - BETTER_TOGETHER_CLIENT = 2; - EASY_UNLOCK_HOST = 3; - EASY_UNLOCK_CLIENT = 4; - MAGIC_TETHER_HOST = 5; - MAGIC_TETHER_CLIENT = 6; - SMS_CONNECT_HOST = 7; - SMS_CONNECT_CLIENT = 8; -} - -// A list of "reasons" that can be provided for calling server-side APIs. -// This is particularly important for calls that can be triggered by different -// kinds of events. Please try to keep reasons as generic as possible, so that -// codes can be re-used by various callers in a sensible fashion. -enum InvocationReason { - REASON_UNKNOWN = 0; - // First run of the software package invoking this call - REASON_INITIALIZATION = 1; - // Ordinary periodic actions (e.g. monthly master key rotation) - REASON_PERIODIC = 2; - // Slow-cycle periodic action (e.g. yearly keypair rotation???) - REASON_SLOW_PERIODIC = 3; - // Fast-cycle periodic action (e.g. daily sync for Smart Lock users) - REASON_FAST_PERIODIC = 4; - // Expired state (e.g. expired credentials, or cached entries) was detected - REASON_EXPIRATION = 5; - // An unexpected protocol failure occurred (so attempting to repair state) - REASON_FAILURE_RECOVERY = 6; - // A new account has been added to the device - REASON_NEW_ACCOUNT = 7; - // An existing account on the device has been changed - REASON_CHANGED_ACCOUNT = 8; - // The user toggled the state of a feature (e.g. Smart Lock enabled via BT) - REASON_FEATURE_TOGGLED = 9; - // A "push" from the server caused this action (e.g. a sync tickle) - REASON_SERVER_INITIATED = 10; - // A local address change triggered this (e.g. GCM registration id changed) - REASON_ADDRESS_CHANGE = 11; - // A software update has triggered this - REASON_SOFTWARE_UPDATE = 12; - // A manual action by the user triggered this (e.g. commands sent via adb) - REASON_MANUAL = 13; - // A custom key has been invalidated on the device (e.g. screen lock is - // disabled). - REASON_CUSTOM_KEY_INVALIDATION = 14; - // Periodic action triggered by auth_proximity - REASON_PROXIMITY_PERIODIC = 15; -} - enum Type { ENROLLMENT = 0; TICKLE = 1; @@ -284,25 +74,3 @@ required Type type = 1; optional int32 version = 2 [default = 0]; } - -message Tickle { - // Time after which this tickle should expire - optional fixed64 expiry_time = 1; -} - -message LoginNotificationInfo { - // Time at which the server received the login notification request. - optional fixed64 creation_time = 2; - - // Must correspond to user_id in LoginNotificationRequest, if set. - optional string email = 3; - - // Host where the user's credentials were used to login, if meaningful. - optional string host = 4; - - // Location from where the user's credentials were used, if meaningful. - optional string source = 5; - - // Type of login, e.g. ssh, gnome-screensaver, or web. - optional string event_type = 6; -}
diff --git a/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto b/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto index 7a19739..bbaa5d5 100644 --- a/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto +++ b/nearby/connections/ukey2/ukey2_proto/proto/securemessage.proto
@@ -72,18 +72,6 @@ required bytes body = 2; } -// Must be kept wire-format compatible with HeaderAndBody. Provides the -// SecureMessage code with a consistent wire-format representation that -// remains stable irrespective of protobuf implementation choices. This -// low-level representation of a HeaderAndBody should not be used by -// any code outside of the SecureMessage library implementation/tests. -message HeaderAndBodyInternal { - // A raw (wire-format) byte encoding of a Header, suitable for hashing - required bytes header = 1; - // Payload data - required bytes body = 2; -} - // ------- // The remainder of the messages defined here are provided only for // convenience. They are not needed for SecureMessage proper, but are
diff --git a/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto b/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto index 1edec1f..450541c 100644 --- a/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto +++ b/nearby/connections/ukey2/ukey2_proto/proto/ukey.proto
@@ -87,8 +87,8 @@ // Next protocol that the client wants to speak. optional string next_protocol = 4; - // Other next protocols the client can speak. - repeated string other_next_protocols = 5; + // Next protocols the client can speak. + repeated string next_protocols = 5; } message Ukey2ServerInit {
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs index fb44c51..ee43758 100644 --- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs +++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/device_to_device_messages.rs
@@ -13,7 +13,7 @@ // limitations under the License. // This file is generated by rust-protobuf 3.2.0. Do not edit -// .proto file is parsed by protoc 3.21.12 +// .proto file is parsed by protoc 3.19.1 // @generated // https://github.com/rust-lang/rust-clippy/issues/702
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs index 3ba20e0..e394495 100644 --- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs +++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securegcm.rs
@@ -13,7 +13,7 @@ // limitations under the License. // This file is generated by rust-protobuf 3.2.0. Do not edit -// .proto file is parsed by protoc 3.21.12 +// .proto file is parsed by protoc 3.19.1 // @generated // https://github.com/rust-lang/rust-clippy/issues/702 @@ -41,1562 +41,6 @@ const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0; #[derive(PartialEq,Clone,Default,Debug)] -// @@protoc_insertion_point(message:securegcm.GcmDeviceInfo) -pub struct GcmDeviceInfo { - // message fields - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.android_device_id) - pub android_device_id: ::std::option::Option<u64>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.gcm_registration_id) - pub gcm_registration_id: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.apn_registration_id) - pub apn_registration_id: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.notification_enabled) - pub notification_enabled: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_mac_address) - pub bluetooth_mac_address: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_master_key_hash) - pub device_master_key_hash: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.user_public_key) - pub user_public_key: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_model) - pub device_model: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.locale) - pub locale: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.key_handle) - pub key_handle: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.counter) - pub counter: ::std::option::Option<i64>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_version) - pub device_os_version: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_version_code) - pub device_os_version_code: ::std::option::Option<i64>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_release) - pub device_os_release: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_os_codename) - pub device_os_codename: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_version) - pub device_software_version: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_version_code) - pub device_software_version_code: ::std::option::Option<i64>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_software_package) - pub device_software_package: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_display_diagonal_mils) - pub device_display_diagonal_mils: ::std::option::Option<i32>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_authzen_version) - pub device_authzen_version: ::std::option::Option<i32>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.long_device_id) - pub long_device_id: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_manufacturer) - pub device_manufacturer: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.device_type) - pub device_type: ::std::option::Option<::protobuf::EnumOrUnknown<DeviceType>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.using_secure_screenlock) - pub using_secure_screenlock: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.auto_unlock_screenlock_supported) - pub auto_unlock_screenlock_supported: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.auto_unlock_screenlock_enabled) - pub auto_unlock_screenlock_enabled: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_radio_supported) - pub bluetooth_radio_supported: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.bluetooth_radio_enabled) - pub bluetooth_radio_enabled: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.mobile_data_supported) - pub mobile_data_supported: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.tethering_supported) - pub tethering_supported: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.ble_radio_supported) - pub ble_radio_supported: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.pixel_experience) - pub pixel_experience: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.arc_plus_plus) - pub arc_plus_plus: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.is_screenlock_state_flaky) - pub is_screenlock_state_flaky: ::std::option::Option<bool>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.supported_software_features) - pub supported_software_features: ::std::vec::Vec<::protobuf::EnumOrUnknown<SoftwareFeature>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.enabled_software_features) - pub enabled_software_features: ::std::vec::Vec<::protobuf::EnumOrUnknown<SoftwareFeature>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.enrollment_session_id) - pub enrollment_session_id: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securegcm.GcmDeviceInfo.oauth_token) - pub oauth_token: ::std::option::Option<::std::string::String>, - // special fields - // @@protoc_insertion_point(special_field:securegcm.GcmDeviceInfo.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a GcmDeviceInfo { - fn default() -> &'a GcmDeviceInfo { - <GcmDeviceInfo as ::protobuf::Message>::default_instance() - } -} - -impl GcmDeviceInfo { - pub fn new() -> GcmDeviceInfo { - ::std::default::Default::default() - } - - // optional fixed64 android_device_id = 1; - - pub fn android_device_id(&self) -> u64 { - self.android_device_id.unwrap_or(0) - } - - pub fn clear_android_device_id(&mut self) { - self.android_device_id = ::std::option::Option::None; - } - - pub fn has_android_device_id(&self) -> bool { - self.android_device_id.is_some() - } - - // Param is passed by value, moved - pub fn set_android_device_id(&mut self, v: u64) { - self.android_device_id = ::std::option::Option::Some(v); - } - - // optional bytes gcm_registration_id = 102; - - pub fn gcm_registration_id(&self) -> &[u8] { - match self.gcm_registration_id.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_gcm_registration_id(&mut self) { - self.gcm_registration_id = ::std::option::Option::None; - } - - pub fn has_gcm_registration_id(&self) -> bool { - self.gcm_registration_id.is_some() - } - - // Param is passed by value, moved - pub fn set_gcm_registration_id(&mut self, v: ::std::vec::Vec<u8>) { - self.gcm_registration_id = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_gcm_registration_id(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.gcm_registration_id.is_none() { - self.gcm_registration_id = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.gcm_registration_id.as_mut().unwrap() - } - - // Take field - pub fn take_gcm_registration_id(&mut self) -> ::std::vec::Vec<u8> { - self.gcm_registration_id.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional bytes apn_registration_id = 202; - - pub fn apn_registration_id(&self) -> &[u8] { - match self.apn_registration_id.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_apn_registration_id(&mut self) { - self.apn_registration_id = ::std::option::Option::None; - } - - pub fn has_apn_registration_id(&self) -> bool { - self.apn_registration_id.is_some() - } - - // Param is passed by value, moved - pub fn set_apn_registration_id(&mut self, v: ::std::vec::Vec<u8>) { - self.apn_registration_id = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_apn_registration_id(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.apn_registration_id.is_none() { - self.apn_registration_id = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.apn_registration_id.as_mut().unwrap() - } - - // Take field - pub fn take_apn_registration_id(&mut self) -> ::std::vec::Vec<u8> { - self.apn_registration_id.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional bool notification_enabled = 203; - - pub fn notification_enabled(&self) -> bool { - self.notification_enabled.unwrap_or(true) - } - - pub fn clear_notification_enabled(&mut self) { - self.notification_enabled = ::std::option::Option::None; - } - - pub fn has_notification_enabled(&self) -> bool { - self.notification_enabled.is_some() - } - - // Param is passed by value, moved - pub fn set_notification_enabled(&mut self, v: bool) { - self.notification_enabled = ::std::option::Option::Some(v); - } - - // optional string bluetooth_mac_address = 302; - - pub fn bluetooth_mac_address(&self) -> &str { - match self.bluetooth_mac_address.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_bluetooth_mac_address(&mut self) { - self.bluetooth_mac_address = ::std::option::Option::None; - } - - pub fn has_bluetooth_mac_address(&self) -> bool { - self.bluetooth_mac_address.is_some() - } - - // Param is passed by value, moved - pub fn set_bluetooth_mac_address(&mut self, v: ::std::string::String) { - self.bluetooth_mac_address = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_bluetooth_mac_address(&mut self) -> &mut ::std::string::String { - if self.bluetooth_mac_address.is_none() { - self.bluetooth_mac_address = ::std::option::Option::Some(::std::string::String::new()); - } - self.bluetooth_mac_address.as_mut().unwrap() - } - - // Take field - pub fn take_bluetooth_mac_address(&mut self) -> ::std::string::String { - self.bluetooth_mac_address.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional bytes device_master_key_hash = 103; - - pub fn device_master_key_hash(&self) -> &[u8] { - match self.device_master_key_hash.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_device_master_key_hash(&mut self) { - self.device_master_key_hash = ::std::option::Option::None; - } - - pub fn has_device_master_key_hash(&self) -> bool { - self.device_master_key_hash.is_some() - } - - // Param is passed by value, moved - pub fn set_device_master_key_hash(&mut self, v: ::std::vec::Vec<u8>) { - self.device_master_key_hash = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_master_key_hash(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.device_master_key_hash.is_none() { - self.device_master_key_hash = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.device_master_key_hash.as_mut().unwrap() - } - - // Take field - pub fn take_device_master_key_hash(&mut self) -> ::std::vec::Vec<u8> { - self.device_master_key_hash.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // required bytes user_public_key = 4; - - pub fn user_public_key(&self) -> &[u8] { - match self.user_public_key.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_user_public_key(&mut self) { - self.user_public_key = ::std::option::Option::None; - } - - pub fn has_user_public_key(&self) -> bool { - self.user_public_key.is_some() - } - - // Param is passed by value, moved - pub fn set_user_public_key(&mut self, v: ::std::vec::Vec<u8>) { - self.user_public_key = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_user_public_key(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.user_public_key.is_none() { - self.user_public_key = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.user_public_key.as_mut().unwrap() - } - - // Take field - pub fn take_user_public_key(&mut self) -> ::std::vec::Vec<u8> { - self.user_public_key.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional string device_model = 7; - - pub fn device_model(&self) -> &str { - match self.device_model.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_model(&mut self) { - self.device_model = ::std::option::Option::None; - } - - pub fn has_device_model(&self) -> bool { - self.device_model.is_some() - } - - // Param is passed by value, moved - pub fn set_device_model(&mut self, v: ::std::string::String) { - self.device_model = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_model(&mut self) -> &mut ::std::string::String { - if self.device_model.is_none() { - self.device_model = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_model.as_mut().unwrap() - } - - // Take field - pub fn take_device_model(&mut self) -> ::std::string::String { - self.device_model.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string locale = 8; - - pub fn locale(&self) -> &str { - match self.locale.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_locale(&mut self) { - self.locale = ::std::option::Option::None; - } - - pub fn has_locale(&self) -> bool { - self.locale.is_some() - } - - // Param is passed by value, moved - pub fn set_locale(&mut self, v: ::std::string::String) { - self.locale = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_locale(&mut self) -> &mut ::std::string::String { - if self.locale.is_none() { - self.locale = ::std::option::Option::Some(::std::string::String::new()); - } - self.locale.as_mut().unwrap() - } - - // Take field - pub fn take_locale(&mut self) -> ::std::string::String { - self.locale.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional bytes key_handle = 9; - - pub fn key_handle(&self) -> &[u8] { - match self.key_handle.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_key_handle(&mut self) { - self.key_handle = ::std::option::Option::None; - } - - pub fn has_key_handle(&self) -> bool { - self.key_handle.is_some() - } - - // Param is passed by value, moved - pub fn set_key_handle(&mut self, v: ::std::vec::Vec<u8>) { - self.key_handle = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_key_handle(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.key_handle.is_none() { - self.key_handle = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.key_handle.as_mut().unwrap() - } - - // Take field - pub fn take_key_handle(&mut self) -> ::std::vec::Vec<u8> { - self.key_handle.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional int64 counter = 12; - - pub fn counter(&self) -> i64 { - self.counter.unwrap_or(0i64) - } - - pub fn clear_counter(&mut self) { - self.counter = ::std::option::Option::None; - } - - pub fn has_counter(&self) -> bool { - self.counter.is_some() - } - - // Param is passed by value, moved - pub fn set_counter(&mut self, v: i64) { - self.counter = ::std::option::Option::Some(v); - } - - // optional string device_os_version = 13; - - pub fn device_os_version(&self) -> &str { - match self.device_os_version.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_os_version(&mut self) { - self.device_os_version = ::std::option::Option::None; - } - - pub fn has_device_os_version(&self) -> bool { - self.device_os_version.is_some() - } - - // Param is passed by value, moved - pub fn set_device_os_version(&mut self, v: ::std::string::String) { - self.device_os_version = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_os_version(&mut self) -> &mut ::std::string::String { - if self.device_os_version.is_none() { - self.device_os_version = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_os_version.as_mut().unwrap() - } - - // Take field - pub fn take_device_os_version(&mut self) -> ::std::string::String { - self.device_os_version.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional int64 device_os_version_code = 14; - - pub fn device_os_version_code(&self) -> i64 { - self.device_os_version_code.unwrap_or(0) - } - - pub fn clear_device_os_version_code(&mut self) { - self.device_os_version_code = ::std::option::Option::None; - } - - pub fn has_device_os_version_code(&self) -> bool { - self.device_os_version_code.is_some() - } - - // Param is passed by value, moved - pub fn set_device_os_version_code(&mut self, v: i64) { - self.device_os_version_code = ::std::option::Option::Some(v); - } - - // optional string device_os_release = 15; - - pub fn device_os_release(&self) -> &str { - match self.device_os_release.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_os_release(&mut self) { - self.device_os_release = ::std::option::Option::None; - } - - pub fn has_device_os_release(&self) -> bool { - self.device_os_release.is_some() - } - - // Param is passed by value, moved - pub fn set_device_os_release(&mut self, v: ::std::string::String) { - self.device_os_release = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_os_release(&mut self) -> &mut ::std::string::String { - if self.device_os_release.is_none() { - self.device_os_release = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_os_release.as_mut().unwrap() - } - - // Take field - pub fn take_device_os_release(&mut self) -> ::std::string::String { - self.device_os_release.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string device_os_codename = 16; - - pub fn device_os_codename(&self) -> &str { - match self.device_os_codename.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_os_codename(&mut self) { - self.device_os_codename = ::std::option::Option::None; - } - - pub fn has_device_os_codename(&self) -> bool { - self.device_os_codename.is_some() - } - - // Param is passed by value, moved - pub fn set_device_os_codename(&mut self, v: ::std::string::String) { - self.device_os_codename = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_os_codename(&mut self) -> &mut ::std::string::String { - if self.device_os_codename.is_none() { - self.device_os_codename = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_os_codename.as_mut().unwrap() - } - - // Take field - pub fn take_device_os_codename(&mut self) -> ::std::string::String { - self.device_os_codename.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string device_software_version = 17; - - pub fn device_software_version(&self) -> &str { - match self.device_software_version.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_software_version(&mut self) { - self.device_software_version = ::std::option::Option::None; - } - - pub fn has_device_software_version(&self) -> bool { - self.device_software_version.is_some() - } - - // Param is passed by value, moved - pub fn set_device_software_version(&mut self, v: ::std::string::String) { - self.device_software_version = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_software_version(&mut self) -> &mut ::std::string::String { - if self.device_software_version.is_none() { - self.device_software_version = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_software_version.as_mut().unwrap() - } - - // Take field - pub fn take_device_software_version(&mut self) -> ::std::string::String { - self.device_software_version.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional int64 device_software_version_code = 18; - - pub fn device_software_version_code(&self) -> i64 { - self.device_software_version_code.unwrap_or(0) - } - - pub fn clear_device_software_version_code(&mut self) { - self.device_software_version_code = ::std::option::Option::None; - } - - pub fn has_device_software_version_code(&self) -> bool { - self.device_software_version_code.is_some() - } - - // Param is passed by value, moved - pub fn set_device_software_version_code(&mut self, v: i64) { - self.device_software_version_code = ::std::option::Option::Some(v); - } - - // optional string device_software_package = 19; - - pub fn device_software_package(&self) -> &str { - match self.device_software_package.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_software_package(&mut self) { - self.device_software_package = ::std::option::Option::None; - } - - pub fn has_device_software_package(&self) -> bool { - self.device_software_package.is_some() - } - - // Param is passed by value, moved - pub fn set_device_software_package(&mut self, v: ::std::string::String) { - self.device_software_package = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_software_package(&mut self) -> &mut ::std::string::String { - if self.device_software_package.is_none() { - self.device_software_package = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_software_package.as_mut().unwrap() - } - - // Take field - pub fn take_device_software_package(&mut self) -> ::std::string::String { - self.device_software_package.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional int32 device_display_diagonal_mils = 22; - - pub fn device_display_diagonal_mils(&self) -> i32 { - self.device_display_diagonal_mils.unwrap_or(0) - } - - pub fn clear_device_display_diagonal_mils(&mut self) { - self.device_display_diagonal_mils = ::std::option::Option::None; - } - - pub fn has_device_display_diagonal_mils(&self) -> bool { - self.device_display_diagonal_mils.is_some() - } - - // Param is passed by value, moved - pub fn set_device_display_diagonal_mils(&mut self, v: i32) { - self.device_display_diagonal_mils = ::std::option::Option::Some(v); - } - - // optional int32 device_authzen_version = 24; - - pub fn device_authzen_version(&self) -> i32 { - self.device_authzen_version.unwrap_or(0) - } - - pub fn clear_device_authzen_version(&mut self) { - self.device_authzen_version = ::std::option::Option::None; - } - - pub fn has_device_authzen_version(&self) -> bool { - self.device_authzen_version.is_some() - } - - // Param is passed by value, moved - pub fn set_device_authzen_version(&mut self, v: i32) { - self.device_authzen_version = ::std::option::Option::Some(v); - } - - // optional bytes long_device_id = 29; - - pub fn long_device_id(&self) -> &[u8] { - match self.long_device_id.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_long_device_id(&mut self) { - self.long_device_id = ::std::option::Option::None; - } - - pub fn has_long_device_id(&self) -> bool { - self.long_device_id.is_some() - } - - // Param is passed by value, moved - pub fn set_long_device_id(&mut self, v: ::std::vec::Vec<u8>) { - self.long_device_id = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_long_device_id(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.long_device_id.is_none() { - self.long_device_id = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.long_device_id.as_mut().unwrap() - } - - // Take field - pub fn take_long_device_id(&mut self) -> ::std::vec::Vec<u8> { - self.long_device_id.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional string device_manufacturer = 31; - - pub fn device_manufacturer(&self) -> &str { - match self.device_manufacturer.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_device_manufacturer(&mut self) { - self.device_manufacturer = ::std::option::Option::None; - } - - pub fn has_device_manufacturer(&self) -> bool { - self.device_manufacturer.is_some() - } - - // Param is passed by value, moved - pub fn set_device_manufacturer(&mut self, v: ::std::string::String) { - self.device_manufacturer = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_device_manufacturer(&mut self) -> &mut ::std::string::String { - if self.device_manufacturer.is_none() { - self.device_manufacturer = ::std::option::Option::Some(::std::string::String::new()); - } - self.device_manufacturer.as_mut().unwrap() - } - - // Take field - pub fn take_device_manufacturer(&mut self) -> ::std::string::String { - self.device_manufacturer.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional .securegcm.DeviceType device_type = 32; - - pub fn device_type(&self) -> DeviceType { - match self.device_type { - Some(e) => e.enum_value_or(DeviceType::ANDROID), - None => DeviceType::ANDROID, - } - } - - pub fn clear_device_type(&mut self) { - self.device_type = ::std::option::Option::None; - } - - pub fn has_device_type(&self) -> bool { - self.device_type.is_some() - } - - // Param is passed by value, moved - pub fn set_device_type(&mut self, v: DeviceType) { - self.device_type = ::std::option::Option::Some(::protobuf::EnumOrUnknown::new(v)); - } - - // optional bool using_secure_screenlock = 400; - - pub fn using_secure_screenlock(&self) -> bool { - self.using_secure_screenlock.unwrap_or(false) - } - - pub fn clear_using_secure_screenlock(&mut self) { - self.using_secure_screenlock = ::std::option::Option::None; - } - - pub fn has_using_secure_screenlock(&self) -> bool { - self.using_secure_screenlock.is_some() - } - - // Param is passed by value, moved - pub fn set_using_secure_screenlock(&mut self, v: bool) { - self.using_secure_screenlock = ::std::option::Option::Some(v); - } - - // optional bool auto_unlock_screenlock_supported = 401; - - pub fn auto_unlock_screenlock_supported(&self) -> bool { - self.auto_unlock_screenlock_supported.unwrap_or(false) - } - - pub fn clear_auto_unlock_screenlock_supported(&mut self) { - self.auto_unlock_screenlock_supported = ::std::option::Option::None; - } - - pub fn has_auto_unlock_screenlock_supported(&self) -> bool { - self.auto_unlock_screenlock_supported.is_some() - } - - // Param is passed by value, moved - pub fn set_auto_unlock_screenlock_supported(&mut self, v: bool) { - self.auto_unlock_screenlock_supported = ::std::option::Option::Some(v); - } - - // optional bool auto_unlock_screenlock_enabled = 402; - - pub fn auto_unlock_screenlock_enabled(&self) -> bool { - self.auto_unlock_screenlock_enabled.unwrap_or(false) - } - - pub fn clear_auto_unlock_screenlock_enabled(&mut self) { - self.auto_unlock_screenlock_enabled = ::std::option::Option::None; - } - - pub fn has_auto_unlock_screenlock_enabled(&self) -> bool { - self.auto_unlock_screenlock_enabled.is_some() - } - - // Param is passed by value, moved - pub fn set_auto_unlock_screenlock_enabled(&mut self, v: bool) { - self.auto_unlock_screenlock_enabled = ::std::option::Option::Some(v); - } - - // optional bool bluetooth_radio_supported = 403; - - pub fn bluetooth_radio_supported(&self) -> bool { - self.bluetooth_radio_supported.unwrap_or(false) - } - - pub fn clear_bluetooth_radio_supported(&mut self) { - self.bluetooth_radio_supported = ::std::option::Option::None; - } - - pub fn has_bluetooth_radio_supported(&self) -> bool { - self.bluetooth_radio_supported.is_some() - } - - // Param is passed by value, moved - pub fn set_bluetooth_radio_supported(&mut self, v: bool) { - self.bluetooth_radio_supported = ::std::option::Option::Some(v); - } - - // optional bool bluetooth_radio_enabled = 404; - - pub fn bluetooth_radio_enabled(&self) -> bool { - self.bluetooth_radio_enabled.unwrap_or(false) - } - - pub fn clear_bluetooth_radio_enabled(&mut self) { - self.bluetooth_radio_enabled = ::std::option::Option::None; - } - - pub fn has_bluetooth_radio_enabled(&self) -> bool { - self.bluetooth_radio_enabled.is_some() - } - - // Param is passed by value, moved - pub fn set_bluetooth_radio_enabled(&mut self, v: bool) { - self.bluetooth_radio_enabled = ::std::option::Option::Some(v); - } - - // optional bool mobile_data_supported = 405; - - pub fn mobile_data_supported(&self) -> bool { - self.mobile_data_supported.unwrap_or(false) - } - - pub fn clear_mobile_data_supported(&mut self) { - self.mobile_data_supported = ::std::option::Option::None; - } - - pub fn has_mobile_data_supported(&self) -> bool { - self.mobile_data_supported.is_some() - } - - // Param is passed by value, moved - pub fn set_mobile_data_supported(&mut self, v: bool) { - self.mobile_data_supported = ::std::option::Option::Some(v); - } - - // optional bool tethering_supported = 406; - - pub fn tethering_supported(&self) -> bool { - self.tethering_supported.unwrap_or(false) - } - - pub fn clear_tethering_supported(&mut self) { - self.tethering_supported = ::std::option::Option::None; - } - - pub fn has_tethering_supported(&self) -> bool { - self.tethering_supported.is_some() - } - - // Param is passed by value, moved - pub fn set_tethering_supported(&mut self, v: bool) { - self.tethering_supported = ::std::option::Option::Some(v); - } - - // optional bool ble_radio_supported = 407; - - pub fn ble_radio_supported(&self) -> bool { - self.ble_radio_supported.unwrap_or(false) - } - - pub fn clear_ble_radio_supported(&mut self) { - self.ble_radio_supported = ::std::option::Option::None; - } - - pub fn has_ble_radio_supported(&self) -> bool { - self.ble_radio_supported.is_some() - } - - // Param is passed by value, moved - pub fn set_ble_radio_supported(&mut self, v: bool) { - self.ble_radio_supported = ::std::option::Option::Some(v); - } - - // optional bool pixel_experience = 408; - - pub fn pixel_experience(&self) -> bool { - self.pixel_experience.unwrap_or(false) - } - - pub fn clear_pixel_experience(&mut self) { - self.pixel_experience = ::std::option::Option::None; - } - - pub fn has_pixel_experience(&self) -> bool { - self.pixel_experience.is_some() - } - - // Param is passed by value, moved - pub fn set_pixel_experience(&mut self, v: bool) { - self.pixel_experience = ::std::option::Option::Some(v); - } - - // optional bool arc_plus_plus = 409; - - pub fn arc_plus_plus(&self) -> bool { - self.arc_plus_plus.unwrap_or(false) - } - - pub fn clear_arc_plus_plus(&mut self) { - self.arc_plus_plus = ::std::option::Option::None; - } - - pub fn has_arc_plus_plus(&self) -> bool { - self.arc_plus_plus.is_some() - } - - // Param is passed by value, moved - pub fn set_arc_plus_plus(&mut self, v: bool) { - self.arc_plus_plus = ::std::option::Option::Some(v); - } - - // optional bool is_screenlock_state_flaky = 410; - - pub fn is_screenlock_state_flaky(&self) -> bool { - self.is_screenlock_state_flaky.unwrap_or(false) - } - - pub fn clear_is_screenlock_state_flaky(&mut self) { - self.is_screenlock_state_flaky = ::std::option::Option::None; - } - - pub fn has_is_screenlock_state_flaky(&self) -> bool { - self.is_screenlock_state_flaky.is_some() - } - - // Param is passed by value, moved - pub fn set_is_screenlock_state_flaky(&mut self, v: bool) { - self.is_screenlock_state_flaky = ::std::option::Option::Some(v); - } - - // optional bytes enrollment_session_id = 1000; - - pub fn enrollment_session_id(&self) -> &[u8] { - match self.enrollment_session_id.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_enrollment_session_id(&mut self) { - self.enrollment_session_id = ::std::option::Option::None; - } - - pub fn has_enrollment_session_id(&self) -> bool { - self.enrollment_session_id.is_some() - } - - // Param is passed by value, moved - pub fn set_enrollment_session_id(&mut self, v: ::std::vec::Vec<u8>) { - self.enrollment_session_id = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_enrollment_session_id(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.enrollment_session_id.is_none() { - self.enrollment_session_id = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.enrollment_session_id.as_mut().unwrap() - } - - // Take field - pub fn take_enrollment_session_id(&mut self) -> ::std::vec::Vec<u8> { - self.enrollment_session_id.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // optional string oauth_token = 1001; - - pub fn oauth_token(&self) -> &str { - match self.oauth_token.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_oauth_token(&mut self) { - self.oauth_token = ::std::option::Option::None; - } - - pub fn has_oauth_token(&self) -> bool { - self.oauth_token.is_some() - } - - // Param is passed by value, moved - pub fn set_oauth_token(&mut self, v: ::std::string::String) { - self.oauth_token = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_oauth_token(&mut self) -> &mut ::std::string::String { - if self.oauth_token.is_none() { - self.oauth_token = ::std::option::Option::Some(::std::string::String::new()); - } - self.oauth_token.as_mut().unwrap() - } - - // Take field - pub fn take_oauth_token(&mut self) -> ::std::string::String { - self.oauth_token.take().unwrap_or_else(|| ::std::string::String::new()) - } -} - -impl ::protobuf::Message for GcmDeviceInfo { - const NAME: &'static str = "GcmDeviceInfo"; - - fn is_initialized(&self) -> bool { - if self.user_public_key.is_none() { - return false; - } - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 9 => { - self.android_device_id = ::std::option::Option::Some(is.read_fixed64()?); - }, - 818 => { - self.gcm_registration_id = ::std::option::Option::Some(is.read_bytes()?); - }, - 1618 => { - self.apn_registration_id = ::std::option::Option::Some(is.read_bytes()?); - }, - 1624 => { - self.notification_enabled = ::std::option::Option::Some(is.read_bool()?); - }, - 2418 => { - self.bluetooth_mac_address = ::std::option::Option::Some(is.read_string()?); - }, - 826 => { - self.device_master_key_hash = ::std::option::Option::Some(is.read_bytes()?); - }, - 34 => { - self.user_public_key = ::std::option::Option::Some(is.read_bytes()?); - }, - 58 => { - self.device_model = ::std::option::Option::Some(is.read_string()?); - }, - 66 => { - self.locale = ::std::option::Option::Some(is.read_string()?); - }, - 74 => { - self.key_handle = ::std::option::Option::Some(is.read_bytes()?); - }, - 96 => { - self.counter = ::std::option::Option::Some(is.read_int64()?); - }, - 106 => { - self.device_os_version = ::std::option::Option::Some(is.read_string()?); - }, - 112 => { - self.device_os_version_code = ::std::option::Option::Some(is.read_int64()?); - }, - 122 => { - self.device_os_release = ::std::option::Option::Some(is.read_string()?); - }, - 130 => { - self.device_os_codename = ::std::option::Option::Some(is.read_string()?); - }, - 138 => { - self.device_software_version = ::std::option::Option::Some(is.read_string()?); - }, - 144 => { - self.device_software_version_code = ::std::option::Option::Some(is.read_int64()?); - }, - 154 => { - self.device_software_package = ::std::option::Option::Some(is.read_string()?); - }, - 176 => { - self.device_display_diagonal_mils = ::std::option::Option::Some(is.read_int32()?); - }, - 192 => { - self.device_authzen_version = ::std::option::Option::Some(is.read_int32()?); - }, - 234 => { - self.long_device_id = ::std::option::Option::Some(is.read_bytes()?); - }, - 250 => { - self.device_manufacturer = ::std::option::Option::Some(is.read_string()?); - }, - 256 => { - self.device_type = ::std::option::Option::Some(is.read_enum_or_unknown()?); - }, - 3200 => { - self.using_secure_screenlock = ::std::option::Option::Some(is.read_bool()?); - }, - 3208 => { - self.auto_unlock_screenlock_supported = ::std::option::Option::Some(is.read_bool()?); - }, - 3216 => { - self.auto_unlock_screenlock_enabled = ::std::option::Option::Some(is.read_bool()?); - }, - 3224 => { - self.bluetooth_radio_supported = ::std::option::Option::Some(is.read_bool()?); - }, - 3232 => { - self.bluetooth_radio_enabled = ::std::option::Option::Some(is.read_bool()?); - }, - 3240 => { - self.mobile_data_supported = ::std::option::Option::Some(is.read_bool()?); - }, - 3248 => { - self.tethering_supported = ::std::option::Option::Some(is.read_bool()?); - }, - 3256 => { - self.ble_radio_supported = ::std::option::Option::Some(is.read_bool()?); - }, - 3264 => { - self.pixel_experience = ::std::option::Option::Some(is.read_bool()?); - }, - 3272 => { - self.arc_plus_plus = ::std::option::Option::Some(is.read_bool()?); - }, - 3280 => { - self.is_screenlock_state_flaky = ::std::option::Option::Some(is.read_bool()?); - }, - 3288 => { - self.supported_software_features.push(is.read_enum_or_unknown()?); - }, - 3290 => { - ::protobuf::rt::read_repeated_packed_enum_or_unknown_into(is, &mut self.supported_software_features)? - }, - 3296 => { - self.enabled_software_features.push(is.read_enum_or_unknown()?); - }, - 3298 => { - ::protobuf::rt::read_repeated_packed_enum_or_unknown_into(is, &mut self.enabled_software_features)? - }, - 8002 => { - self.enrollment_session_id = ::std::option::Option::Some(is.read_bytes()?); - }, - 8010 => { - self.oauth_token = ::std::option::Option::Some(is.read_string()?); - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if let Some(v) = self.android_device_id { - my_size += 1 + 8; - } - if let Some(v) = self.gcm_registration_id.as_ref() { - my_size += ::protobuf::rt::bytes_size(102, &v); - } - if let Some(v) = self.apn_registration_id.as_ref() { - my_size += ::protobuf::rt::bytes_size(202, &v); - } - if let Some(v) = self.notification_enabled { - my_size += 2 + 1; - } - if let Some(v) = self.bluetooth_mac_address.as_ref() { - my_size += ::protobuf::rt::string_size(302, &v); - } - if let Some(v) = self.device_master_key_hash.as_ref() { - my_size += ::protobuf::rt::bytes_size(103, &v); - } - if let Some(v) = self.user_public_key.as_ref() { - my_size += ::protobuf::rt::bytes_size(4, &v); - } - if let Some(v) = self.device_model.as_ref() { - my_size += ::protobuf::rt::string_size(7, &v); - } - if let Some(v) = self.locale.as_ref() { - my_size += ::protobuf::rt::string_size(8, &v); - } - if let Some(v) = self.key_handle.as_ref() { - my_size += ::protobuf::rt::bytes_size(9, &v); - } - if let Some(v) = self.counter { - my_size += ::protobuf::rt::int64_size(12, v); - } - if let Some(v) = self.device_os_version.as_ref() { - my_size += ::protobuf::rt::string_size(13, &v); - } - if let Some(v) = self.device_os_version_code { - my_size += ::protobuf::rt::int64_size(14, v); - } - if let Some(v) = self.device_os_release.as_ref() { - my_size += ::protobuf::rt::string_size(15, &v); - } - if let Some(v) = self.device_os_codename.as_ref() { - my_size += ::protobuf::rt::string_size(16, &v); - } - if let Some(v) = self.device_software_version.as_ref() { - my_size += ::protobuf::rt::string_size(17, &v); - } - if let Some(v) = self.device_software_version_code { - my_size += ::protobuf::rt::int64_size(18, v); - } - if let Some(v) = self.device_software_package.as_ref() { - my_size += ::protobuf::rt::string_size(19, &v); - } - if let Some(v) = self.device_display_diagonal_mils { - my_size += ::protobuf::rt::int32_size(22, v); - } - if let Some(v) = self.device_authzen_version { - my_size += ::protobuf::rt::int32_size(24, v); - } - if let Some(v) = self.long_device_id.as_ref() { - my_size += ::protobuf::rt::bytes_size(29, &v); - } - if let Some(v) = self.device_manufacturer.as_ref() { - my_size += ::protobuf::rt::string_size(31, &v); - } - if let Some(v) = self.device_type { - my_size += ::protobuf::rt::int32_size(32, v.value()); - } - if let Some(v) = self.using_secure_screenlock { - my_size += 2 + 1; - } - if let Some(v) = self.auto_unlock_screenlock_supported { - my_size += 2 + 1; - } - if let Some(v) = self.auto_unlock_screenlock_enabled { - my_size += 2 + 1; - } - if let Some(v) = self.bluetooth_radio_supported { - my_size += 2 + 1; - } - if let Some(v) = self.bluetooth_radio_enabled { - my_size += 2 + 1; - } - if let Some(v) = self.mobile_data_supported { - my_size += 2 + 1; - } - if let Some(v) = self.tethering_supported { - my_size += 2 + 1; - } - if let Some(v) = self.ble_radio_supported { - my_size += 2 + 1; - } - if let Some(v) = self.pixel_experience { - my_size += 2 + 1; - } - if let Some(v) = self.arc_plus_plus { - my_size += 2 + 1; - } - if let Some(v) = self.is_screenlock_state_flaky { - my_size += 2 + 1; - } - for value in &self.supported_software_features { - my_size += ::protobuf::rt::int32_size(411, value.value()); - }; - for value in &self.enabled_software_features { - my_size += ::protobuf::rt::int32_size(412, value.value()); - }; - if let Some(v) = self.enrollment_session_id.as_ref() { - my_size += ::protobuf::rt::bytes_size(1000, &v); - } - if let Some(v) = self.oauth_token.as_ref() { - my_size += ::protobuf::rt::string_size(1001, &v); - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if let Some(v) = self.android_device_id { - os.write_fixed64(1, v)?; - } - if let Some(v) = self.gcm_registration_id.as_ref() { - os.write_bytes(102, v)?; - } - if let Some(v) = self.apn_registration_id.as_ref() { - os.write_bytes(202, v)?; - } - if let Some(v) = self.notification_enabled { - os.write_bool(203, v)?; - } - if let Some(v) = self.bluetooth_mac_address.as_ref() { - os.write_string(302, v)?; - } - if let Some(v) = self.device_master_key_hash.as_ref() { - os.write_bytes(103, v)?; - } - if let Some(v) = self.user_public_key.as_ref() { - os.write_bytes(4, v)?; - } - if let Some(v) = self.device_model.as_ref() { - os.write_string(7, v)?; - } - if let Some(v) = self.locale.as_ref() { - os.write_string(8, v)?; - } - if let Some(v) = self.key_handle.as_ref() { - os.write_bytes(9, v)?; - } - if let Some(v) = self.counter { - os.write_int64(12, v)?; - } - if let Some(v) = self.device_os_version.as_ref() { - os.write_string(13, v)?; - } - if let Some(v) = self.device_os_version_code { - os.write_int64(14, v)?; - } - if let Some(v) = self.device_os_release.as_ref() { - os.write_string(15, v)?; - } - if let Some(v) = self.device_os_codename.as_ref() { - os.write_string(16, v)?; - } - if let Some(v) = self.device_software_version.as_ref() { - os.write_string(17, v)?; - } - if let Some(v) = self.device_software_version_code { - os.write_int64(18, v)?; - } - if let Some(v) = self.device_software_package.as_ref() { - os.write_string(19, v)?; - } - if let Some(v) = self.device_display_diagonal_mils { - os.write_int32(22, v)?; - } - if let Some(v) = self.device_authzen_version { - os.write_int32(24, v)?; - } - if let Some(v) = self.long_device_id.as_ref() { - os.write_bytes(29, v)?; - } - if let Some(v) = self.device_manufacturer.as_ref() { - os.write_string(31, v)?; - } - if let Some(v) = self.device_type { - os.write_enum(32, ::protobuf::EnumOrUnknown::value(&v))?; - } - if let Some(v) = self.using_secure_screenlock { - os.write_bool(400, v)?; - } - if let Some(v) = self.auto_unlock_screenlock_supported { - os.write_bool(401, v)?; - } - if let Some(v) = self.auto_unlock_screenlock_enabled { - os.write_bool(402, v)?; - } - if let Some(v) = self.bluetooth_radio_supported { - os.write_bool(403, v)?; - } - if let Some(v) = self.bluetooth_radio_enabled { - os.write_bool(404, v)?; - } - if let Some(v) = self.mobile_data_supported { - os.write_bool(405, v)?; - } - if let Some(v) = self.tethering_supported { - os.write_bool(406, v)?; - } - if let Some(v) = self.ble_radio_supported { - os.write_bool(407, v)?; - } - if let Some(v) = self.pixel_experience { - os.write_bool(408, v)?; - } - if let Some(v) = self.arc_plus_plus { - os.write_bool(409, v)?; - } - if let Some(v) = self.is_screenlock_state_flaky { - os.write_bool(410, v)?; - } - for v in &self.supported_software_features { - os.write_enum(411, ::protobuf::EnumOrUnknown::value(v))?; - }; - for v in &self.enabled_software_features { - os.write_enum(412, ::protobuf::EnumOrUnknown::value(v))?; - }; - if let Some(v) = self.enrollment_session_id.as_ref() { - os.write_bytes(1000, v)?; - } - if let Some(v) = self.oauth_token.as_ref() { - os.write_string(1001, v)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> GcmDeviceInfo { - GcmDeviceInfo::new() - } - - fn clear(&mut self) { - self.android_device_id = ::std::option::Option::None; - self.gcm_registration_id = ::std::option::Option::None; - self.apn_registration_id = ::std::option::Option::None; - self.notification_enabled = ::std::option::Option::None; - self.bluetooth_mac_address = ::std::option::Option::None; - self.device_master_key_hash = ::std::option::Option::None; - self.user_public_key = ::std::option::Option::None; - self.device_model = ::std::option::Option::None; - self.locale = ::std::option::Option::None; - self.key_handle = ::std::option::Option::None; - self.counter = ::std::option::Option::None; - self.device_os_version = ::std::option::Option::None; - self.device_os_version_code = ::std::option::Option::None; - self.device_os_release = ::std::option::Option::None; - self.device_os_codename = ::std::option::Option::None; - self.device_software_version = ::std::option::Option::None; - self.device_software_version_code = ::std::option::Option::None; - self.device_software_package = ::std::option::Option::None; - self.device_display_diagonal_mils = ::std::option::Option::None; - self.device_authzen_version = ::std::option::Option::None; - self.long_device_id = ::std::option::Option::None; - self.device_manufacturer = ::std::option::Option::None; - self.device_type = ::std::option::Option::None; - self.using_secure_screenlock = ::std::option::Option::None; - self.auto_unlock_screenlock_supported = ::std::option::Option::None; - self.auto_unlock_screenlock_enabled = ::std::option::Option::None; - self.bluetooth_radio_supported = ::std::option::Option::None; - self.bluetooth_radio_enabled = ::std::option::Option::None; - self.mobile_data_supported = ::std::option::Option::None; - self.tethering_supported = ::std::option::Option::None; - self.ble_radio_supported = ::std::option::Option::None; - self.pixel_experience = ::std::option::Option::None; - self.arc_plus_plus = ::std::option::Option::None; - self.is_screenlock_state_flaky = ::std::option::Option::None; - self.supported_software_features.clear(); - self.enabled_software_features.clear(); - self.enrollment_session_id = ::std::option::Option::None; - self.oauth_token = ::std::option::Option::None; - self.special_fields.clear(); - } - - fn default_instance() -> &'static GcmDeviceInfo { - static instance: GcmDeviceInfo = GcmDeviceInfo { - android_device_id: ::std::option::Option::None, - gcm_registration_id: ::std::option::Option::None, - apn_registration_id: ::std::option::Option::None, - notification_enabled: ::std::option::Option::None, - bluetooth_mac_address: ::std::option::Option::None, - device_master_key_hash: ::std::option::Option::None, - user_public_key: ::std::option::Option::None, - device_model: ::std::option::Option::None, - locale: ::std::option::Option::None, - key_handle: ::std::option::Option::None, - counter: ::std::option::Option::None, - device_os_version: ::std::option::Option::None, - device_os_version_code: ::std::option::Option::None, - device_os_release: ::std::option::Option::None, - device_os_codename: ::std::option::Option::None, - device_software_version: ::std::option::Option::None, - device_software_version_code: ::std::option::Option::None, - device_software_package: ::std::option::Option::None, - device_display_diagonal_mils: ::std::option::Option::None, - device_authzen_version: ::std::option::Option::None, - long_device_id: ::std::option::Option::None, - device_manufacturer: ::std::option::Option::None, - device_type: ::std::option::Option::None, - using_secure_screenlock: ::std::option::Option::None, - auto_unlock_screenlock_supported: ::std::option::Option::None, - auto_unlock_screenlock_enabled: ::std::option::Option::None, - bluetooth_radio_supported: ::std::option::Option::None, - bluetooth_radio_enabled: ::std::option::Option::None, - mobile_data_supported: ::std::option::Option::None, - tethering_supported: ::std::option::Option::None, - ble_radio_supported: ::std::option::Option::None, - pixel_experience: ::std::option::Option::None, - arc_plus_plus: ::std::option::Option::None, - is_screenlock_state_flaky: ::std::option::Option::None, - supported_software_features: ::std::vec::Vec::new(), - enabled_software_features: ::std::vec::Vec::new(), - enrollment_session_id: ::std::option::Option::None, - oauth_token: ::std::option::Option::None, - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:securegcm.GcmMetadata) pub struct GcmMetadata { // message fields @@ -1743,669 +187,6 @@ } } -#[derive(PartialEq,Clone,Default,Debug)] -// @@protoc_insertion_point(message:securegcm.Tickle) -pub struct Tickle { - // message fields - // @@protoc_insertion_point(field:securegcm.Tickle.expiry_time) - pub expiry_time: ::std::option::Option<u64>, - // special fields - // @@protoc_insertion_point(special_field:securegcm.Tickle.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a Tickle { - fn default() -> &'a Tickle { - <Tickle as ::protobuf::Message>::default_instance() - } -} - -impl Tickle { - pub fn new() -> Tickle { - ::std::default::Default::default() - } - - // optional fixed64 expiry_time = 1; - - pub fn expiry_time(&self) -> u64 { - self.expiry_time.unwrap_or(0) - } - - pub fn clear_expiry_time(&mut self) { - self.expiry_time = ::std::option::Option::None; - } - - pub fn has_expiry_time(&self) -> bool { - self.expiry_time.is_some() - } - - // Param is passed by value, moved - pub fn set_expiry_time(&mut self, v: u64) { - self.expiry_time = ::std::option::Option::Some(v); - } -} - -impl ::protobuf::Message for Tickle { - const NAME: &'static str = "Tickle"; - - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 9 => { - self.expiry_time = ::std::option::Option::Some(is.read_fixed64()?); - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if let Some(v) = self.expiry_time { - my_size += 1 + 8; - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if let Some(v) = self.expiry_time { - os.write_fixed64(1, v)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> Tickle { - Tickle::new() - } - - fn clear(&mut self) { - self.expiry_time = ::std::option::Option::None; - self.special_fields.clear(); - } - - fn default_instance() -> &'static Tickle { - static instance: Tickle = Tickle { - expiry_time: ::std::option::Option::None, - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -#[derive(PartialEq,Clone,Default,Debug)] -// @@protoc_insertion_point(message:securegcm.LoginNotificationInfo) -pub struct LoginNotificationInfo { - // message fields - // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.creation_time) - pub creation_time: ::std::option::Option<u64>, - // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.email) - pub email: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.host) - pub host: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.source) - pub source: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.LoginNotificationInfo.event_type) - pub event_type: ::std::option::Option<::std::string::String>, - // special fields - // @@protoc_insertion_point(special_field:securegcm.LoginNotificationInfo.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a LoginNotificationInfo { - fn default() -> &'a LoginNotificationInfo { - <LoginNotificationInfo as ::protobuf::Message>::default_instance() - } -} - -impl LoginNotificationInfo { - pub fn new() -> LoginNotificationInfo { - ::std::default::Default::default() - } - - // optional fixed64 creation_time = 2; - - pub fn creation_time(&self) -> u64 { - self.creation_time.unwrap_or(0) - } - - pub fn clear_creation_time(&mut self) { - self.creation_time = ::std::option::Option::None; - } - - pub fn has_creation_time(&self) -> bool { - self.creation_time.is_some() - } - - // Param is passed by value, moved - pub fn set_creation_time(&mut self, v: u64) { - self.creation_time = ::std::option::Option::Some(v); - } - - // optional string email = 3; - - pub fn email(&self) -> &str { - match self.email.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_email(&mut self) { - self.email = ::std::option::Option::None; - } - - pub fn has_email(&self) -> bool { - self.email.is_some() - } - - // Param is passed by value, moved - pub fn set_email(&mut self, v: ::std::string::String) { - self.email = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_email(&mut self) -> &mut ::std::string::String { - if self.email.is_none() { - self.email = ::std::option::Option::Some(::std::string::String::new()); - } - self.email.as_mut().unwrap() - } - - // Take field - pub fn take_email(&mut self) -> ::std::string::String { - self.email.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string host = 4; - - pub fn host(&self) -> &str { - match self.host.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_host(&mut self) { - self.host = ::std::option::Option::None; - } - - pub fn has_host(&self) -> bool { - self.host.is_some() - } - - // Param is passed by value, moved - pub fn set_host(&mut self, v: ::std::string::String) { - self.host = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_host(&mut self) -> &mut ::std::string::String { - if self.host.is_none() { - self.host = ::std::option::Option::Some(::std::string::String::new()); - } - self.host.as_mut().unwrap() - } - - // Take field - pub fn take_host(&mut self) -> ::std::string::String { - self.host.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string source = 5; - - pub fn source(&self) -> &str { - match self.source.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_source(&mut self) { - self.source = ::std::option::Option::None; - } - - pub fn has_source(&self) -> bool { - self.source.is_some() - } - - // Param is passed by value, moved - pub fn set_source(&mut self, v: ::std::string::String) { - self.source = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_source(&mut self) -> &mut ::std::string::String { - if self.source.is_none() { - self.source = ::std::option::Option::Some(::std::string::String::new()); - } - self.source.as_mut().unwrap() - } - - // Take field - pub fn take_source(&mut self) -> ::std::string::String { - self.source.take().unwrap_or_else(|| ::std::string::String::new()) - } - - // optional string event_type = 6; - - pub fn event_type(&self) -> &str { - match self.event_type.as_ref() { - Some(v) => v, - None => "", - } - } - - pub fn clear_event_type(&mut self) { - self.event_type = ::std::option::Option::None; - } - - pub fn has_event_type(&self) -> bool { - self.event_type.is_some() - } - - // Param is passed by value, moved - pub fn set_event_type(&mut self, v: ::std::string::String) { - self.event_type = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_event_type(&mut self) -> &mut ::std::string::String { - if self.event_type.is_none() { - self.event_type = ::std::option::Option::Some(::std::string::String::new()); - } - self.event_type.as_mut().unwrap() - } - - // Take field - pub fn take_event_type(&mut self) -> ::std::string::String { - self.event_type.take().unwrap_or_else(|| ::std::string::String::new()) - } -} - -impl ::protobuf::Message for LoginNotificationInfo { - const NAME: &'static str = "LoginNotificationInfo"; - - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 17 => { - self.creation_time = ::std::option::Option::Some(is.read_fixed64()?); - }, - 26 => { - self.email = ::std::option::Option::Some(is.read_string()?); - }, - 34 => { - self.host = ::std::option::Option::Some(is.read_string()?); - }, - 42 => { - self.source = ::std::option::Option::Some(is.read_string()?); - }, - 50 => { - self.event_type = ::std::option::Option::Some(is.read_string()?); - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if let Some(v) = self.creation_time { - my_size += 1 + 8; - } - if let Some(v) = self.email.as_ref() { - my_size += ::protobuf::rt::string_size(3, &v); - } - if let Some(v) = self.host.as_ref() { - my_size += ::protobuf::rt::string_size(4, &v); - } - if let Some(v) = self.source.as_ref() { - my_size += ::protobuf::rt::string_size(5, &v); - } - if let Some(v) = self.event_type.as_ref() { - my_size += ::protobuf::rt::string_size(6, &v); - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if let Some(v) = self.creation_time { - os.write_fixed64(2, v)?; - } - if let Some(v) = self.email.as_ref() { - os.write_string(3, v)?; - } - if let Some(v) = self.host.as_ref() { - os.write_string(4, v)?; - } - if let Some(v) = self.source.as_ref() { - os.write_string(5, v)?; - } - if let Some(v) = self.event_type.as_ref() { - os.write_string(6, v)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> LoginNotificationInfo { - LoginNotificationInfo::new() - } - - fn clear(&mut self) { - self.creation_time = ::std::option::Option::None; - self.email = ::std::option::Option::None; - self.host = ::std::option::Option::None; - self.source = ::std::option::Option::None; - self.event_type = ::std::option::Option::None; - self.special_fields.clear(); - } - - fn default_instance() -> &'static LoginNotificationInfo { - static instance: LoginNotificationInfo = LoginNotificationInfo { - creation_time: ::std::option::Option::None, - email: ::std::option::Option::None, - host: ::std::option::Option::None, - source: ::std::option::Option::None, - event_type: ::std::option::Option::None, - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:securegcm.AppleDeviceDiagonalMils) -pub enum AppleDeviceDiagonalMils { - // @@protoc_insertion_point(enum_value:securegcm.AppleDeviceDiagonalMils.APPLE_PHONE) - APPLE_PHONE = 4000, - // @@protoc_insertion_point(enum_value:securegcm.AppleDeviceDiagonalMils.APPLE_PAD) - APPLE_PAD = 7900, -} - -impl ::protobuf::Enum for AppleDeviceDiagonalMils { - const NAME: &'static str = "AppleDeviceDiagonalMils"; - - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option<AppleDeviceDiagonalMils> { - match value { - 4000 => ::std::option::Option::Some(AppleDeviceDiagonalMils::APPLE_PHONE), - 7900 => ::std::option::Option::Some(AppleDeviceDiagonalMils::APPLE_PAD), - _ => ::std::option::Option::None - } - } - - const VALUES: &'static [AppleDeviceDiagonalMils] = &[ - AppleDeviceDiagonalMils::APPLE_PHONE, - AppleDeviceDiagonalMils::APPLE_PAD, - ]; -} - -// Note, `Default` is implemented although default value is not 0 -impl ::std::default::Default for AppleDeviceDiagonalMils { - fn default() -> Self { - AppleDeviceDiagonalMils::APPLE_PHONE - } -} - - -#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:securegcm.DeviceType) -pub enum DeviceType { - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.UNKNOWN) - UNKNOWN = 0, - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.ANDROID) - ANDROID = 1, - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.CHROME) - CHROME = 2, - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.IOS) - IOS = 3, - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.BROWSER) - BROWSER = 4, - // @@protoc_insertion_point(enum_value:securegcm.DeviceType.OSX) - OSX = 5, -} - -impl ::protobuf::Enum for DeviceType { - const NAME: &'static str = "DeviceType"; - - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option<DeviceType> { - match value { - 0 => ::std::option::Option::Some(DeviceType::UNKNOWN), - 1 => ::std::option::Option::Some(DeviceType::ANDROID), - 2 => ::std::option::Option::Some(DeviceType::CHROME), - 3 => ::std::option::Option::Some(DeviceType::IOS), - 4 => ::std::option::Option::Some(DeviceType::BROWSER), - 5 => ::std::option::Option::Some(DeviceType::OSX), - _ => ::std::option::Option::None - } - } - - const VALUES: &'static [DeviceType] = &[ - DeviceType::UNKNOWN, - DeviceType::ANDROID, - DeviceType::CHROME, - DeviceType::IOS, - DeviceType::BROWSER, - DeviceType::OSX, - ]; -} - -impl ::std::default::Default for DeviceType { - fn default() -> Self { - DeviceType::UNKNOWN - } -} - - -#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:securegcm.SoftwareFeature) -pub enum SoftwareFeature { - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.UNKNOWN_FEATURE) - UNKNOWN_FEATURE = 0, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.BETTER_TOGETHER_HOST) - BETTER_TOGETHER_HOST = 1, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.BETTER_TOGETHER_CLIENT) - BETTER_TOGETHER_CLIENT = 2, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.EASY_UNLOCK_HOST) - EASY_UNLOCK_HOST = 3, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.EASY_UNLOCK_CLIENT) - EASY_UNLOCK_CLIENT = 4, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.MAGIC_TETHER_HOST) - MAGIC_TETHER_HOST = 5, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.MAGIC_TETHER_CLIENT) - MAGIC_TETHER_CLIENT = 6, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.SMS_CONNECT_HOST) - SMS_CONNECT_HOST = 7, - // @@protoc_insertion_point(enum_value:securegcm.SoftwareFeature.SMS_CONNECT_CLIENT) - SMS_CONNECT_CLIENT = 8, -} - -impl ::protobuf::Enum for SoftwareFeature { - const NAME: &'static str = "SoftwareFeature"; - - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option<SoftwareFeature> { - match value { - 0 => ::std::option::Option::Some(SoftwareFeature::UNKNOWN_FEATURE), - 1 => ::std::option::Option::Some(SoftwareFeature::BETTER_TOGETHER_HOST), - 2 => ::std::option::Option::Some(SoftwareFeature::BETTER_TOGETHER_CLIENT), - 3 => ::std::option::Option::Some(SoftwareFeature::EASY_UNLOCK_HOST), - 4 => ::std::option::Option::Some(SoftwareFeature::EASY_UNLOCK_CLIENT), - 5 => ::std::option::Option::Some(SoftwareFeature::MAGIC_TETHER_HOST), - 6 => ::std::option::Option::Some(SoftwareFeature::MAGIC_TETHER_CLIENT), - 7 => ::std::option::Option::Some(SoftwareFeature::SMS_CONNECT_HOST), - 8 => ::std::option::Option::Some(SoftwareFeature::SMS_CONNECT_CLIENT), - _ => ::std::option::Option::None - } - } - - const VALUES: &'static [SoftwareFeature] = &[ - SoftwareFeature::UNKNOWN_FEATURE, - SoftwareFeature::BETTER_TOGETHER_HOST, - SoftwareFeature::BETTER_TOGETHER_CLIENT, - SoftwareFeature::EASY_UNLOCK_HOST, - SoftwareFeature::EASY_UNLOCK_CLIENT, - SoftwareFeature::MAGIC_TETHER_HOST, - SoftwareFeature::MAGIC_TETHER_CLIENT, - SoftwareFeature::SMS_CONNECT_HOST, - SoftwareFeature::SMS_CONNECT_CLIENT, - ]; -} - -impl ::std::default::Default for SoftwareFeature { - fn default() -> Self { - SoftwareFeature::UNKNOWN_FEATURE - } -} - - -#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:securegcm.InvocationReason) -pub enum InvocationReason { - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_UNKNOWN) - REASON_UNKNOWN = 0, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_INITIALIZATION) - REASON_INITIALIZATION = 1, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_PERIODIC) - REASON_PERIODIC = 2, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SLOW_PERIODIC) - REASON_SLOW_PERIODIC = 3, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FAST_PERIODIC) - REASON_FAST_PERIODIC = 4, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_EXPIRATION) - REASON_EXPIRATION = 5, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FAILURE_RECOVERY) - REASON_FAILURE_RECOVERY = 6, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_NEW_ACCOUNT) - REASON_NEW_ACCOUNT = 7, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_CHANGED_ACCOUNT) - REASON_CHANGED_ACCOUNT = 8, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_FEATURE_TOGGLED) - REASON_FEATURE_TOGGLED = 9, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SERVER_INITIATED) - REASON_SERVER_INITIATED = 10, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_ADDRESS_CHANGE) - REASON_ADDRESS_CHANGE = 11, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_SOFTWARE_UPDATE) - REASON_SOFTWARE_UPDATE = 12, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_MANUAL) - REASON_MANUAL = 13, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_CUSTOM_KEY_INVALIDATION) - REASON_CUSTOM_KEY_INVALIDATION = 14, - // @@protoc_insertion_point(enum_value:securegcm.InvocationReason.REASON_PROXIMITY_PERIODIC) - REASON_PROXIMITY_PERIODIC = 15, -} - -impl ::protobuf::Enum for InvocationReason { - const NAME: &'static str = "InvocationReason"; - - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option<InvocationReason> { - match value { - 0 => ::std::option::Option::Some(InvocationReason::REASON_UNKNOWN), - 1 => ::std::option::Option::Some(InvocationReason::REASON_INITIALIZATION), - 2 => ::std::option::Option::Some(InvocationReason::REASON_PERIODIC), - 3 => ::std::option::Option::Some(InvocationReason::REASON_SLOW_PERIODIC), - 4 => ::std::option::Option::Some(InvocationReason::REASON_FAST_PERIODIC), - 5 => ::std::option::Option::Some(InvocationReason::REASON_EXPIRATION), - 6 => ::std::option::Option::Some(InvocationReason::REASON_FAILURE_RECOVERY), - 7 => ::std::option::Option::Some(InvocationReason::REASON_NEW_ACCOUNT), - 8 => ::std::option::Option::Some(InvocationReason::REASON_CHANGED_ACCOUNT), - 9 => ::std::option::Option::Some(InvocationReason::REASON_FEATURE_TOGGLED), - 10 => ::std::option::Option::Some(InvocationReason::REASON_SERVER_INITIATED), - 11 => ::std::option::Option::Some(InvocationReason::REASON_ADDRESS_CHANGE), - 12 => ::std::option::Option::Some(InvocationReason::REASON_SOFTWARE_UPDATE), - 13 => ::std::option::Option::Some(InvocationReason::REASON_MANUAL), - 14 => ::std::option::Option::Some(InvocationReason::REASON_CUSTOM_KEY_INVALIDATION), - 15 => ::std::option::Option::Some(InvocationReason::REASON_PROXIMITY_PERIODIC), - _ => ::std::option::Option::None - } - } - - const VALUES: &'static [InvocationReason] = &[ - InvocationReason::REASON_UNKNOWN, - InvocationReason::REASON_INITIALIZATION, - InvocationReason::REASON_PERIODIC, - InvocationReason::REASON_SLOW_PERIODIC, - InvocationReason::REASON_FAST_PERIODIC, - InvocationReason::REASON_EXPIRATION, - InvocationReason::REASON_FAILURE_RECOVERY, - InvocationReason::REASON_NEW_ACCOUNT, - InvocationReason::REASON_CHANGED_ACCOUNT, - InvocationReason::REASON_FEATURE_TOGGLED, - InvocationReason::REASON_SERVER_INITIATED, - InvocationReason::REASON_ADDRESS_CHANGE, - InvocationReason::REASON_SOFTWARE_UPDATE, - InvocationReason::REASON_MANUAL, - InvocationReason::REASON_CUSTOM_KEY_INVALIDATION, - InvocationReason::REASON_PROXIMITY_PERIODIC, - ]; -} - -impl ::std::default::Default for InvocationReason { - fn default() -> Self { - InvocationReason::REASON_UNKNOWN - } -} - - #[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] // @@protoc_insertion_point(enum:securegcm.Type) pub enum Type {
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs index d11c330..cafd900 100644 --- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs +++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/securemessage.rs
@@ -13,7 +13,7 @@ // limitations under the License. // This file is generated by rust-protobuf 3.2.0. Do not edit -// .proto file is parsed by protoc 3.21.12 +// .proto file is parsed by protoc 3.19.1 // @generated // https://github.com/rust-lang/rust-clippy/issues/702 @@ -803,187 +803,6 @@ } #[derive(PartialEq,Clone,Default,Debug)] -// @@protoc_insertion_point(message:securemessage.HeaderAndBodyInternal) -pub struct HeaderAndBodyInternal { - // message fields - // @@protoc_insertion_point(field:securemessage.HeaderAndBodyInternal.header) - pub header: ::std::option::Option<::std::vec::Vec<u8>>, - // @@protoc_insertion_point(field:securemessage.HeaderAndBodyInternal.body) - pub body: ::std::option::Option<::std::vec::Vec<u8>>, - // special fields - // @@protoc_insertion_point(special_field:securemessage.HeaderAndBodyInternal.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a HeaderAndBodyInternal { - fn default() -> &'a HeaderAndBodyInternal { - <HeaderAndBodyInternal as ::protobuf::Message>::default_instance() - } -} - -impl HeaderAndBodyInternal { - pub fn new() -> HeaderAndBodyInternal { - ::std::default::Default::default() - } - - // required bytes header = 1; - - pub fn header(&self) -> &[u8] { - match self.header.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_header(&mut self) { - self.header = ::std::option::Option::None; - } - - pub fn has_header(&self) -> bool { - self.header.is_some() - } - - // Param is passed by value, moved - pub fn set_header(&mut self, v: ::std::vec::Vec<u8>) { - self.header = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_header(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.header.is_none() { - self.header = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.header.as_mut().unwrap() - } - - // Take field - pub fn take_header(&mut self) -> ::std::vec::Vec<u8> { - self.header.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } - - // required bytes body = 2; - - pub fn body(&self) -> &[u8] { - match self.body.as_ref() { - Some(v) => v, - None => &[], - } - } - - pub fn clear_body(&mut self) { - self.body = ::std::option::Option::None; - } - - pub fn has_body(&self) -> bool { - self.body.is_some() - } - - // Param is passed by value, moved - pub fn set_body(&mut self, v: ::std::vec::Vec<u8>) { - self.body = ::std::option::Option::Some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_body(&mut self) -> &mut ::std::vec::Vec<u8> { - if self.body.is_none() { - self.body = ::std::option::Option::Some(::std::vec::Vec::new()); - } - self.body.as_mut().unwrap() - } - - // Take field - pub fn take_body(&mut self) -> ::std::vec::Vec<u8> { - self.body.take().unwrap_or_else(|| ::std::vec::Vec::new()) - } -} - -impl ::protobuf::Message for HeaderAndBodyInternal { - const NAME: &'static str = "HeaderAndBodyInternal"; - - fn is_initialized(&self) -> bool { - if self.header.is_none() { - return false; - } - if self.body.is_none() { - return false; - } - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 10 => { - self.header = ::std::option::Option::Some(is.read_bytes()?); - }, - 18 => { - self.body = ::std::option::Option::Some(is.read_bytes()?); - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if let Some(v) = self.header.as_ref() { - my_size += ::protobuf::rt::bytes_size(1, &v); - } - if let Some(v) = self.body.as_ref() { - my_size += ::protobuf::rt::bytes_size(2, &v); - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if let Some(v) = self.header.as_ref() { - os.write_bytes(1, v)?; - } - if let Some(v) = self.body.as_ref() { - os.write_bytes(2, v)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> HeaderAndBodyInternal { - HeaderAndBodyInternal::new() - } - - fn clear(&mut self) { - self.header = ::std::option::Option::None; - self.body = ::std::option::Option::None; - self.special_fields.clear(); - } - - fn default_instance() -> &'static HeaderAndBodyInternal { - static instance: HeaderAndBodyInternal = HeaderAndBodyInternal { - header: ::std::option::Option::None, - body: ::std::option::Option::None, - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:securemessage.EcP256PublicKey) pub struct EcP256PublicKey { // message fields
diff --git a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs index 4535937..648f2ac 100644 --- a/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs +++ b/nearby/connections/ukey2/ukey2_proto/src/ukey2_all_proto/ukey.rs
@@ -13,7 +13,7 @@ // limitations under the License. // This file is generated by rust-protobuf 3.2.0. Do not edit -// .proto file is parsed by protoc 3.21.12 +// .proto file is parsed by protoc 3.19.1 // @generated // https://github.com/rust-lang/rust-clippy/issues/702 @@ -499,8 +499,8 @@ pub cipher_commitments: ::std::vec::Vec<ukey2client_init::CipherCommitment>, // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.next_protocol) pub next_protocol: ::std::option::Option<::std::string::String>, - // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.other_next_protocols) - pub other_next_protocols: ::std::vec::Vec<::std::string::String>, + // @@protoc_insertion_point(field:securegcm.Ukey2ClientInit.next_protocols) + pub next_protocols: ::std::vec::Vec<::std::string::String>, // special fields // @@protoc_insertion_point(special_field:securegcm.Ukey2ClientInit.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -632,7 +632,7 @@ self.next_protocol = ::std::option::Option::Some(is.read_string()?); }, 42 => { - self.other_next_protocols.push(is.read_string()?); + self.next_protocols.push(is.read_string()?); }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; @@ -659,7 +659,7 @@ if let Some(v) = self.next_protocol.as_ref() { my_size += ::protobuf::rt::string_size(4, &v); } - for value in &self.other_next_protocols { + for value in &self.next_protocols { my_size += ::protobuf::rt::string_size(5, &value); }; my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); @@ -680,7 +680,7 @@ if let Some(v) = self.next_protocol.as_ref() { os.write_string(4, v)?; } - for v in &self.other_next_protocols { + for v in &self.next_protocols { os.write_string(5, &v)?; }; os.write_unknown_fields(self.special_fields.unknown_fields())?; @@ -704,7 +704,7 @@ self.random = ::std::option::Option::None; self.cipher_commitments.clear(); self.next_protocol = ::std::option::Option::None; - self.other_next_protocols.clear(); + self.next_protocols.clear(); self.special_fields.clear(); } @@ -714,7 +714,7 @@ random: ::std::option::Option::None, cipher_commitments: ::std::vec::Vec::new(), next_protocol: ::std::option::Option::None, - other_next_protocols: ::std::vec::Vec::new(), + next_protocols: ::std::vec::Vec::new(), special_fields: ::protobuf::SpecialFields::new(), }; &instance
diff --git a/nearby/connections/ukey2/ukey2_shell/Cargo.toml b/nearby/connections/ukey2/ukey2_shell/Cargo.toml index 2ac12fa..c5c84ea 100644 --- a/nearby/connections/ukey2/ukey2_shell/Cargo.toml +++ b/nearby/connections/ukey2/ukey2_shell/Cargo.toml
@@ -9,6 +9,5 @@ [dependencies] crypto_provider_rustcrypto = { workspace = true, features = [ "alloc" ] } -ukey2_rs = { version = "0.1.0", path = "../ukey2" } ukey2_connections = { version = "0.1.0", path = "../ukey2_connections" } clap = { workspace = true, features = ["std", "derive"] }
diff --git a/nearby/connections/ukey2/ukey2_shell/src/main.rs b/nearby/connections/ukey2/ukey2_shell/src/main.rs index 3eca7b0..c50ee93 100644 --- a/nearby/connections/ukey2/ukey2_shell/src/main.rs +++ b/nearby/connections/ukey2/ukey2_shell/src/main.rs
@@ -25,10 +25,9 @@ use crypto_provider_rustcrypto::RustCrypto; use ukey2_connections::{ - D2DConnectionContextV1, D2DHandshakeContext, InitiatorD2DHandshakeContext, - ServerD2DHandshakeContext, + D2DConnectionContextV1, D2DHandshakeContext, HandshakeImplementation, + InitiatorD2DHandshakeContext, NextProtocol, ServerD2DHandshakeContext, }; -use ukey2_rs::HandshakeImplementation; const MODE_INITIATOR: &str = "initiator"; const MODE_RESPONDER: &str = "responder"; @@ -139,6 +138,7 @@ fn run_as_initiator(&self) -> bool { let mut initiator_ctx = InitiatorD2DHandshakeContext::<RustCrypto, _>::new( HandshakeImplementation::PublicKeyInProtobuf, + vec![NextProtocol::Aes256CbcHmacSha256, NextProtocol::Aes256GcmSiv], ); write_frame(initiator_ctx.get_next_handshake_message().unwrap()); let server_init_msg = read_frame(); @@ -166,6 +166,7 @@ fn run_as_responder(&self) -> bool { let mut server_ctx = ServerD2DHandshakeContext::<RustCrypto, _>::new( HandshakeImplementation::PublicKeyInProtobuf, + &[NextProtocol::Aes256GcmSiv, NextProtocol::Aes256CbcHmacSha256], ); let initiator_init_msg = read_frame(); server_ctx.handle_handshake_message(initiator_init_msg.as_slice()).unwrap();
diff --git a/nearby/crypto/crypto_provider/Cargo.toml b/nearby/crypto/crypto_provider/Cargo.toml index a31f5fa..bafdfcc 100644 --- a/nearby/crypto/crypto_provider/Cargo.toml +++ b/nearby/crypto/crypto_provider/Cargo.toml
@@ -22,7 +22,6 @@ std = [] alloc = [] test_vectors = [] -test_boringssl = ["crypto_provider_default/boringssl"] raw_private_key_permit = [] [[bench]]
diff --git a/nearby/crypto/crypto_provider/src/ed25519.rs b/nearby/crypto/crypto_provider/src/ed25519.rs index 7002335..94e98d0 100644 --- a/nearby/crypto/crypto_provider/src/ed25519.rs +++ b/nearby/crypto/crypto_provider/src/ed25519.rs
@@ -14,16 +14,7 @@ use core::fmt::Debug; -/// Collection of types used to provide an implementation of ed25519, the Edwards-curve Digital -/// Signature Algorithm scheme using sha-512 (sha2) and Curve25519 -pub trait Ed25519Provider { - /// The keypair which includes both public and secret halves of an asymmetric key. - type KeyPair: KeyPair<PublicKey = Self::PublicKey, Signature = Self::Signature>; - /// The ed25519 public key, used when verifying a message - type PublicKey: PublicKey<Signature = Self::Signature>; - /// The ed25519 signature which is the result of signing a message - type Signature: Signature; -} +// User-facing, crypto-provider independent structs /// The length of a ed25519 `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; @@ -74,35 +65,139 @@ /// Useful for when you want a data-structure to be /// crypto-provider independent and contain a private key. #[derive(Clone)] -pub struct PrivateKey { - wrapped: RawPrivateKey, -} +pub struct PrivateKey(RawPrivateKey); impl PrivateKey { /// Derives the public key corresponding to this private key. - pub fn derive_public_key<E: Ed25519Provider>(&self) -> E::PublicKey { + pub fn derive_public_key<E: Ed25519Provider>(&self) -> PublicKey { let key_pair = E::KeyPair::from_private_key(self); - key_pair.public() + key_pair.public_key().to_external() } + /// Sign the given message and return a digital signature + pub fn sign<E: Ed25519Provider>(&self, msg: &[u8]) -> Signature { + let key_pair = E::KeyPair::from_private_key(self); + key_pair.sign(msg).to_external() + } + /// Generate an ed25519 private key from a CSPRNG + /// generate is not available in `no-std`. + #[cfg(feature = "std")] + pub fn generate<E: Ed25519Provider>() -> Self { + let key_pair = E::KeyPair::generate(); + key_pair.private_key() + } + /// Returns the raw bytes of this private key. /// This operation is only possible while holding a [`RawPrivateKeyPermit`]. pub fn raw_private_key(&self, _permit: &RawPrivateKeyPermit) -> RawPrivateKey { - self.wrapped + self.0 } /// Constructs a private key from the raw bytes of the key. /// This operation is only possible while holding a [`RawPrivateKeyPermit`]. pub fn from_raw_private_key(wrapped: RawPrivateKey, _permit: &RawPrivateKeyPermit) -> Self { - Self { wrapped } + PrivateKey(wrapped) } } +/// error returned when bad bytes are provided to generate keypair +#[derive(Debug)] +pub struct InvalidPublicKeyBytes; + +/// Error returned if the verification on the signature + message fails +#[derive(Debug)] +pub struct SignatureError; + +/// A crypto-provider-independent representation of a valid +/// public key for an ed25519 key-pair in the Edwards Y-format. +/// +/// Useful for when you want a data-structure to be crypto-provider +/// independent and contain a public key. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct PublicKey(RawPublicKey); + +impl PublicKey { + /// Attempts to parse a public key from an array of bytes. + /// If the input is not in the Edwards Y-format, this method + /// will yield an `InvalidPublicKeyBytes` error. + pub fn from_bytes<E: Ed25519Provider>( + wrapped: RawPublicKey, + ) -> Result<Self, InvalidPublicKeyBytes> { + // Simply verify that we can construct the crypto-provider-dependent variant. + let _ = <E::PublicKey as PublicKeyImpl>::from_bytes(&wrapped)?; + Ok(PublicKey(wrapped)) + } + /// Converts this public-key into the raw bytes of this public-key. + pub fn into_bytes(self) -> RawPublicKey { + self.0 + } + + /// Converts this crypto-provider-independent public key to a crypto-provider's internal rep. + #[allow(clippy::expect_used)] + fn as_internal<E: Ed25519Provider>(&self) -> E::PublicKey { + <E::PublicKey as PublicKeyImpl>::from_bytes(&self.0) + .expect("Public key bytes validated upon construction.") + } + + /// Succeeds if the signature on the given message is verified + /// by this public key. + pub fn verify_strict<E: Ed25519Provider>( + &self, + message: &[u8], + signature: Signature, + ) -> Result<(), SignatureError> { + let public_key = self.as_internal::<E>(); + let signature = signature.as_internal::<E>(); + public_key.verify_strict(message, &signature) + } +} + +/// A crypto-provider-independent representation of an Ed25519 signature. +/// The underlying representation here can be any arbitrary bytes - verifying +/// code handles determining whether/not the signature actually corresponds +/// to a real Ed25519 signature and matches the given public key. +#[derive(Clone)] +pub struct Signature(RawSignature); + +impl From<RawSignature> for Signature { + fn from(wrapped: RawSignature) -> Self { + Signature(wrapped) + } +} + +impl Signature { + /// Constructs a signature from raw bytes. + pub fn new(wrapped: RawSignature) -> Self { + Signature(wrapped) + } + /// Transforms this signature back into raw bytes. + pub fn to_bytes(self) -> RawSignature { + self.0 + } + /// Converts this crypto-provider-independent signature to a crypto-provider's internal rep. + fn as_internal<E: Ed25519Provider>(&self) -> E::Signature { + <E::Signature as SignatureImpl>::from_bytes(&self.0) + } +} + +// Implementor-facing crypto-provider-internal traits. + +/// Collection of types used to provide an implementation of ed25519, the Edwards-curve Digital +/// Signature Algorithm scheme using sha-512 (sha2) and Curve25519 +pub trait Ed25519Provider { + /// The internal representation of a keypair which includes both public and secret halves of an asymmetric key. + type KeyPair: KeyPairImpl<PublicKey = Self::PublicKey, Signature = Self::Signature>; + /// The internal representation of an ed25519 public key, used when verifying a message + type PublicKey: PublicKeyImpl<Signature = Self::Signature>; + /// The internal representation of an ed25519 signature which is the result of signing a message + type Signature: SignatureImpl; +} + /// The keypair which includes both public and secret halves of an asymmetric key. -pub trait KeyPair: Sized { +pub trait KeyPairImpl: Sized { /// The ed25519 public key, used when verifying a message - type PublicKey: PublicKey; + type PublicKey: PublicKeyImpl; /// The ed25519 signature returned when signing a message - type Signature: Signature; + type Signature: SignatureImpl; /// Returns the private key bytes of the `KeyPair`. /// This operation is only possible while holding a [`RawPrivateKeyPermit`]. @@ -120,7 +215,7 @@ // since the way that we're exposing it would require a valid // [`RawPrivateKeyPermit`] to extract them again. let wrapped = self.raw_private_key(&RawPrivateKeyPermit::new()); - PrivateKey { wrapped } + PrivateKey(wrapped) } /// Builds a key-pair from a [`PrivateKey`], given in an opaque form. @@ -132,7 +227,7 @@ // the bytes of the private key, since the way that they // were originally expressed would still require a valid // [`RawPrivateKeyPermit`] to access them. - let raw_private_key = &private_key.wrapped; + let raw_private_key = &private_key.0; Self::from_raw_private_key(raw_private_key, &RawPrivateKeyPermit::new()) } @@ -145,24 +240,33 @@ fn generate() -> Self; /// getter function for the Public Key of the key pair - fn public(&self) -> Self::PublicKey; + fn public_key(&self) -> Self::PublicKey; } /// An ed25519 signature -pub trait Signature: Sized { - /// Create a new signature from a byte slice, and return an error on an invalid signature - /// An `Ok` result does not guarantee that the Signature is valid, however it will catch a - /// number of invalid signatures relatively inexpensively. +pub trait SignatureImpl: Sized { + /// Create a new signature from a fixed size byte array. This represents a container for the + /// byte serialization of an Ed25519 signature, and does not necessarily represent well-formed + /// field or curve elements. + /// + /// Signature verification libraries are expected to reject invalid field + /// elements at the time a signature is verified (not constructed). fn from_bytes(bytes: &RawSignature) -> Self; /// Returns a slice of the signature bytes fn to_bytes(&self) -> RawSignature; + + /// Returns a crypto-provider-independent `Signature` from this implementation-specific struct. + fn to_external(&self) -> Signature { + let wrapped = self.to_bytes(); + Signature(wrapped) + } } /// An ed25519 public key -pub trait PublicKey { +pub trait PublicKeyImpl { /// the signature type being used by verify - type Signature: Signature; + type Signature: SignatureImpl; /// Builds this public key from an array of bytes in /// the format yielded by `to_bytes`. @@ -173,6 +277,12 @@ /// Yields the bytes of the public key fn to_bytes(&self) -> RawPublicKey; + /// Returns a crypto-provider-independent `PublicKey` from this implementation-specific struct. + fn to_external(&self) -> PublicKey { + let wrapped = self.to_bytes(); + PublicKey(wrapped) + } + /// Succeeds if the signature was a valid signature created by this Keypair on the prehashed_message. fn verify_strict( &self, @@ -180,11 +290,3 @@ signature: &Self::Signature, ) -> Result<(), SignatureError>; } - -/// error returned when bad bytes are provided to generate keypair -#[derive(Debug)] -pub struct InvalidPublicKeyBytes; - -/// Error returned if the verification on the signature + message fails -#[derive(Debug)] -pub struct SignatureError;
diff --git a/nearby/crypto/crypto_provider_boringssl/Cargo.lock b/nearby/crypto/crypto_provider_boringssl/Cargo.lock index 432c546..356a65d 100644 --- a/nearby/crypto/crypto_provider_boringssl/Cargo.lock +++ b/nearby/crypto/crypto_provider_boringssl/Cargo.lock
@@ -66,6 +66,12 @@ ] [[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] name = "getrandom" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -95,6 +101,15 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -333,6 +348,7 @@ version = "0.1.0" dependencies = [ "hex", + "itertools", "serde_json", ]
diff --git a/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs b/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs index e411df1..0841e2b 100644 --- a/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs +++ b/nearby/crypto/crypto_provider_boringssl/src/ed25519.rs
@@ -14,7 +14,7 @@ use crypto_provider::ed25519::{ InvalidPublicKeyBytes, RawPrivateKey, RawPrivateKeyPermit, RawPublicKey, RawSignature, - Signature as _, SignatureError, + SignatureError, SignatureImpl, }; pub struct Ed25519; @@ -27,7 +27,7 @@ pub struct KeyPair(bssl_crypto::ed25519::PrivateKey); -impl crypto_provider::ed25519::KeyPair for KeyPair { +impl crypto_provider::ed25519::KeyPairImpl for KeyPair { type PublicKey = PublicKey; type Signature = Signature; @@ -51,14 +51,14 @@ Self(bssl_crypto::ed25519::PrivateKey::generate()) } - fn public(&self) -> Self::PublicKey { + fn public_key(&self) -> Self::PublicKey { PublicKey(self.0.to_public()) } } pub struct Signature(bssl_crypto::ed25519::Signature); -impl crypto_provider::ed25519::Signature for Signature { +impl crypto_provider::ed25519::SignatureImpl for Signature { fn from_bytes(bytes: &RawSignature) -> Self { Self(bssl_crypto::ed25519::Signature::from(*bytes)) } @@ -70,7 +70,7 @@ pub struct PublicKey(bssl_crypto::ed25519::PublicKey); -impl crypto_provider::ed25519::PublicKey for PublicKey { +impl crypto_provider::ed25519::PublicKeyImpl for PublicKey { type Signature = Signature; fn from_bytes(bytes: &RawPublicKey) -> Result<Self, InvalidPublicKeyBytes>
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs index 46abfc3..ee01101 100644 --- a/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs +++ b/nearby/crypto/crypto_provider_rustcrypto/src/ed25519.rs
@@ -16,7 +16,7 @@ use crypto_provider::ed25519::{ InvalidPublicKeyBytes, RawPrivateKey, RawPrivateKeyPermit, RawPublicKey, RawSignature, - Signature as _, SignatureError, PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH, + SignatureError, SignatureImpl, PRIVATE_KEY_LENGTH, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH, }; pub struct Ed25519; @@ -29,7 +29,7 @@ pub struct KeyPair(ed25519_dalek::SigningKey); -impl crypto_provider::ed25519::KeyPair for KeyPair { +impl crypto_provider::ed25519::KeyPairImpl for KeyPair { type PublicKey = PublicKey; type Signature = Signature; @@ -54,14 +54,14 @@ Self(ed25519_dalek::SigningKey::generate(&mut csprng)) } - fn public(&self) -> Self::PublicKey { + fn public_key(&self) -> Self::PublicKey { PublicKey(self.0.verifying_key()) } } pub struct Signature(ed25519_dalek::Signature); -impl crypto_provider::ed25519::Signature for Signature { +impl crypto_provider::ed25519::SignatureImpl for Signature { fn from_bytes(bytes: &RawSignature) -> Self { Self(ed25519_dalek::Signature::from_bytes(bytes)) } @@ -73,7 +73,7 @@ pub struct PublicKey(ed25519_dalek::VerifyingKey); -impl crypto_provider::ed25519::PublicKey for PublicKey { +impl crypto_provider::ed25519::PublicKeyImpl for PublicKey { type Signature = Signature; fn from_bytes(bytes: &RawPublicKey) -> Result<Self, InvalidPublicKeyBytes>
diff --git a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs index 2985dec..97cf6a7 100644 --- a/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs +++ b/nearby/crypto/crypto_provider_rustcrypto/src/lib.rs
@@ -56,7 +56,7 @@ } } -/// The the RustCrypto backed struct which implements CryptoProvider +/// The RustCrypto backed struct which implements CryptoProvider #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct RustCryptoImpl<R: CryptoRng + SeedableRng + RngCore> { _marker: PhantomData<R>,
diff --git a/nearby/crypto/crypto_provider_stubs/src/lib.rs b/nearby/crypto/crypto_provider_stubs/src/lib.rs index 83d54ff..35bc274 100644 --- a/nearby/crypto/crypto_provider_stubs/src/lib.rs +++ b/nearby/crypto/crypto_provider_stubs/src/lib.rs
@@ -29,8 +29,8 @@ Aes, Aes128Key, Aes256Key, AesBlock, AesCipher, AesDecryptCipher, AesEncryptCipher, }, ed25519::{ - self, Ed25519Provider, InvalidPublicKeyBytes, KeyPair, RawPrivateKey, RawPrivateKeyPermit, - RawPublicKey, RawSignature, Signature, SignatureError, + self, Ed25519Provider, InvalidPublicKeyBytes, KeyPairImpl, RawPrivateKey, + RawPrivateKeyPermit, RawPublicKey, RawSignature, SignatureError, SignatureImpl, }, elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey}, hkdf::{Hkdf, InvalidLength}, @@ -477,7 +477,7 @@ type Signature = SignatureStubs; } -impl ed25519::PublicKey for PublicKeyStubs { +impl ed25519::PublicKeyImpl for PublicKeyStubs { type Signature = SignatureStubs; fn from_bytes(bytes: &RawPublicKey) -> Result<Self, InvalidPublicKeyBytes> @@ -502,7 +502,7 @@ pub struct SignatureStubs; -impl Signature for SignatureStubs { +impl SignatureImpl for SignatureStubs { fn from_bytes(_bytes: &RawSignature) -> Self { unimplemented!() } @@ -514,7 +514,7 @@ pub struct KeyPairStubs; -impl KeyPair for KeyPairStubs { +impl KeyPairImpl for KeyPairStubs { type PublicKey = PublicKeyStubs; type Signature = SignatureStubs; @@ -537,7 +537,7 @@ unimplemented!() } - fn public(&self) -> Self::PublicKey { + fn public_key(&self) -> Self::PublicKey { unimplemented!() } }
diff --git a/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock b/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock index 72c827b..844b537 100644 --- a/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock +++ b/nearby/crypto/crypto_provider_test/fuzz/Cargo.lock
@@ -434,9 +434,9 @@ [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ]
diff --git a/nearby/crypto/crypto_provider_test/fuzz/Cargo.toml b/nearby/crypto/crypto_provider_test/fuzz/Cargo.toml index 5bfc9ab..10c3e5c 100644 --- a/nearby/crypto/crypto_provider_test/fuzz/Cargo.toml +++ b/nearby/crypto/crypto_provider_test/fuzz/Cargo.toml
@@ -8,24 +8,18 @@ cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4" -crypto_provider = { path = "../../crypto_provider" } -crypto_provider_default = { path = "../../crypto_provider_default", default-features = false } -arbitrary = { version = "1.2.3", features = ["derive"] } +crypto_provider.workspace = true +crypto_provider_default = { workspace = true, default-features = false } +derive_fuzztest.workspace = true + +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true [features] default = ["crypto_provider_default/default"] boringssl = ["crypto_provider_default/boringssl"] -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[profile.release] -debug = 1 - [[bin]] name = "fuzz_p256" -path = "fuzz_targets/fuzz_p256.rs" -test = false +path = "src/bin/fuzz_p256.rs" doc = false
diff --git a/nearby/crypto/crypto_provider_test/fuzz/fuzz_targets/fuzz_p256.rs b/nearby/crypto/crypto_provider_test/fuzz/src/bin/fuzz_p256.rs similarity index 86% rename from nearby/crypto/crypto_provider_test/fuzz/fuzz_targets/fuzz_p256.rs rename to nearby/crypto/crypto_provider_test/fuzz/src/bin/fuzz_p256.rs index 00a0624..f5d3111 100644 --- a/nearby/crypto/crypto_provider_test/fuzz/fuzz_targets/fuzz_p256.rs +++ b/nearby/crypto/crypto_provider_test/fuzz/src/bin/fuzz_p256.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,24 +13,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use arbitrary::Arbitrary; use crypto_provider::{ elliptic_curve::EcdhProvider, p256::{P256PublicKey, P256}, CryptoProvider, }; use crypto_provider_default::CryptoProviderImpl; -use libfuzzer_sys::fuzz_target; - -#[derive(Debug, Arbitrary)] -struct FuzzInput { - bytes: Vec<u8>, -} +use derive_fuzztest::fuzztest; type P256PublicKeyAlias<P> = <<P as CryptoProvider>::P256 as EcdhProvider<P256>>::PublicKey; -fuzz_target!(|input: FuzzInput| { - let pubkey = P256PublicKeyAlias::<CryptoProviderImpl>::from_sec1_bytes(&input.bytes); +#[fuzztest] +fn test(input: Vec<u8>) { + let pubkey = P256PublicKeyAlias::<CryptoProviderImpl>::from_sec1_bytes(&input); if let Ok(key) = pubkey { let (x, y) = key .to_affine_coordinates() @@ -40,4 +35,4 @@ .expect("Creating public key from affine coordinates should succeed"); assert_eq!(key, recreated_pubkey); } -}); +}
diff --git a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs index 88eaf32..4a84a67 100644 --- a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs +++ b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm.rs
@@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use alloc::vec::Vec; use core::marker; use hex_literal::hex;
diff --git a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs index 56d2215..672b9ce 100644 --- a/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs +++ b/nearby/crypto/crypto_provider_test/src/aead/aes_gcm_siv.rs
@@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use alloc::vec::Vec; use core::marker; use hex_literal::hex;
diff --git a/nearby/crypto/crypto_provider_test/src/ed25519.rs b/nearby/crypto/crypto_provider_test/src/ed25519.rs index 0fdb484..f2bc7ef 100644 --- a/nearby/crypto/crypto_provider_test/src/ed25519.rs +++ b/nearby/crypto/crypto_provider_test/src/ed25519.rs
@@ -15,11 +15,8 @@ extern crate alloc; extern crate std; -use alloc::borrow::ToOwned; -use alloc::string::String; -use alloc::vec::Vec; use crypto_provider::ed25519::{ - Ed25519Provider, KeyPair, PublicKey, RawPrivateKeyPermit, RawSignature, Signature, + Ed25519Provider, KeyPairImpl, PublicKeyImpl, RawPrivateKeyPermit, RawSignature, SignatureImpl, }; use wycheproof::TestResult; @@ -149,7 +146,7 @@ sig.as_slice().try_into().expect("Test signature should be the correct length"), ); - let pub_key = kp.public(); + let pub_key = kp.public_key(); assert_eq!(pub_key.to_bytes().as_slice(), expected_pub_key.as_slice()); pub_key.verify_strict(msg.as_slice(), &signature).map_err(|_| "verify failed")?;
diff --git a/nearby/crypto/crypto_provider_test/src/hkdf.rs b/nearby/crypto/crypto_provider_test/src/hkdf.rs index d664230..d8982fd 100644 --- a/nearby/crypto/crypto_provider_test/src/hkdf.rs +++ b/nearby/crypto/crypto_provider_test/src/hkdf.rs
@@ -14,8 +14,6 @@ extern crate alloc; pub use crate::prelude::*; use crate::CryptoProvider; -use alloc::vec; -use alloc::vec::Vec; use core::iter; use core::marker::PhantomData; use crypto_provider::hkdf::Hkdf; @@ -51,7 +49,7 @@ const MAX_SHA256_LENGTH: usize = 255 * (256 / 8); // =8160 -/// +/// Content of a HKDF test-case. pub struct Test<'a> { ikm: &'a [u8], salt: &'a [u8], @@ -79,9 +77,8 @@ assert_eq!(okm, expected); } -// Test Vectors from https://tools.ietf.org/html/rfc5869. #[rustfmt::skip] - /// + /// Test Vectors from <https://tools.ietf.org/html/rfc5869>. pub fn test_rfc5869_sha256<C: CryptoProvider>(_: PhantomData<C>) { let tests = [ Test { @@ -152,7 +149,7 @@ } } -/// +/// Tests a bunch of HKDFs of differing lengths. pub fn test_lengths<C: CryptoProvider>(_: PhantomData<C>) { let hkdf = C::HkdfSha256::new(None, &[]); let mut longest = vec![0u8; MAX_SHA256_LENGTH]; @@ -173,28 +170,28 @@ } } -/// +/// Tests an HKDF with the maximum length for Sha256. pub fn test_max_length<C: CryptoProvider>(_: PhantomData<C>) { let hkdf = C::HkdfSha256::new(Some(&[]), &[]); let mut okm = vec![0u8; MAX_SHA256_LENGTH]; assert!(hkdf.expand(&[], &mut okm).is_ok()); } -/// +/// Tests an HKDF above the maximum length for Sha256. pub fn test_max_length_exceeded<C: CryptoProvider>(_: PhantomData<C>) { let hkdf = C::HkdfSha256::new(Some(&[]), &[]); let mut okm = vec![0u8; MAX_SHA256_LENGTH + 1]; assert!(hkdf.expand(&[], &mut okm).is_err()); } -/// +/// Tests an HKDF with an unsupported length. pub fn test_unsupported_length<C: CryptoProvider>(_: PhantomData<C>) { let hkdf = C::HkdfSha256::new(Some(&[]), &[]); let mut okm = vec![0u8; 90000]; assert!(hkdf.expand(&[], &mut okm).is_err()); } -/// +/// Tests HKDF-Expand on the concatenation of info components. pub fn test_expand_multi_info<C: CryptoProvider>(_: PhantomData<C>) { let info_components = &[ &b"09090909090909090909090909090909090909090909"[..], @@ -231,12 +228,12 @@ } } -/// +/// Runs hkdf test vectors using Sha256. pub fn run_hkdf_sha256_vectors<C: CryptoProvider>(_: PhantomData<C>) { run_hkdf_test_vectors::<C::HkdfSha256>(HashAlg::Sha256) } -/// +/// Runs hkdf test vectors using Sha512. pub fn run_hkdf_sha512_vectors<C: CryptoProvider>(_: PhantomData<C>) { run_hkdf_test_vectors::<C::HkdfSha512>(HashAlg::Sha512) } @@ -246,7 +243,7 @@ Sha512, } -/// +/// Runs the wycheproof test vectors for the given hashing algorithm. fn run_hkdf_test_vectors<K: Hkdf>(hash: HashAlg) { let test_name = match hash { HashAlg::Sha256 => wycheproof::hkdf::TestName::HkdfSha256,
diff --git a/nearby/crypto/crypto_provider_test/src/lib.rs b/nearby/crypto/crypto_provider_test/src/lib.rs index 2209a3e..6ba6413 100644 --- a/nearby/crypto/crypto_provider_test/src/lib.rs +++ b/nearby/crypto/crypto_provider_test/src/lib.rs
@@ -13,7 +13,7 @@ // limitations under the License. extern crate alloc; -use alloc::{format, string::String}; +use alloc::format; use core::marker::PhantomData; use crypto_provider::CryptoProvider; @@ -47,7 +47,7 @@ pub type CryptoProviderTestCase<T> = fn(PhantomData<T>); #[derive(Debug)] -pub(crate) struct TestError(String); +pub(crate) struct TestError(#[allow(unused)] String); impl TestError { pub(crate) fn new<D: core::fmt::Debug>(value: D) -> Self {
diff --git a/nearby/crypto/crypto_provider_test/src/sha2.rs b/nearby/crypto/crypto_provider_test/src/sha2.rs index 66a3025..b10ac9a 100644 --- a/nearby/crypto/crypto_provider_test/src/sha2.rs +++ b/nearby/crypto/crypto_provider_test/src/sha2.rs
@@ -16,7 +16,6 @@ extern crate std; use crate::prelude::*; use crate::CryptoProvider; -use alloc::vec::Vec; use core::{marker::PhantomData, str::FromStr}; use crypto_provider::sha2::{Sha256, Sha512}; use hex::FromHex;
diff --git a/nearby/crypto/rand_core_05_adapter/Cargo.toml b/nearby/crypto/rand_core_05_adapter/Cargo.toml deleted file mode 100644 index 1a02526..0000000 --- a/nearby/crypto/rand_core_05_adapter/Cargo.toml +++ /dev/null
@@ -1,13 +0,0 @@ -[package] -name = "rand_core_05_adapter" -version.workspace = true -edition.workspace = true -publish.workspace = true - -[lints] -workspace = true - -[dependencies] -rand.workspace = true -# an older rand_core used by ed25519-dalek so we can adapt newer rand to it -rand_core05 = { package = "rand_core", version = "0.5.1" }
diff --git a/nearby/crypto/rand_core_05_adapter/src/lib.rs b/nearby/crypto/rand_core_05_adapter/src/lib.rs deleted file mode 100644 index 9de0020..0000000 --- a/nearby/crypto/rand_core_05_adapter/src/lib.rs +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Adapter for using rand_core 0.5 RNGs with code that expects rand_core 0.5 RNGs. - -#![no_std] - -/// A trivial adapter to expose rand 1.0/rand_core 0.6 rngs to ed25519-dalek's rand_core 0.5 types, -/// which we import under a separate name so there's no clash. -pub struct RandWrapper<'r, R: rand::RngCore + rand::CryptoRng> { - rng: &'r mut R, -} - -impl<'r, R: rand::RngCore + rand::CryptoRng> RandWrapper<'r, R> { - /// Build a rand_core 0.5 compatible wrapper around the provided rng. - pub fn from(rng: &'r mut R) -> RandWrapper<'r, R> { - RandWrapper { rng } - } -} - -impl<'r, R: rand::RngCore + rand::CryptoRng> rand_core05::RngCore for RandWrapper<'r, R> { - fn next_u32(&mut self) -> u32 { - self.rng.next_u32() - } - - fn next_u64(&mut self) -> u64 { - self.rng.next_u64() - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.rng.fill_bytes(dest) - } - - #[cfg(feature = "std")] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core05::Error> { - self.rng.try_fill_bytes(dest).map_err(|e| rand_core05::Error::new(e.take_inner())) - } - - #[cfg(not(feature = "std"))] - #[allow(clippy::expect_used)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core05::Error> { - self.rng - .try_fill_bytes(dest) - .map_err(|e| rand_core05::Error::from(e.code().expect("for no_std this is never none"))) - } -} - -impl<'r, R: rand::RngCore + rand::CryptoRng> rand_core05::CryptoRng for RandWrapper<'r, R> { - // marker trait -}
diff --git a/nearby/deny.toml b/nearby/deny.toml index d9f6dc8..30dd444 100644 --- a/nearby/deny.toml +++ b/nearby/deny.toml
@@ -48,8 +48,8 @@ # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - # criterion 0.4.0 depends on a version of atty w/unaligned reads - "RUSTSEC-2021-0145", + # comment explaining why we have to ignore it + # "RUSTSEC-FOO", ] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories @@ -85,7 +85,8 @@ "ISC", "Unicode-DFS-2016", "OpenSSL", - "Unlicense" + "Unlicense", + "CC0-1.0" ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses @@ -94,7 +95,7 @@ #"Nokia", ] # Lint level for licenses considered copyleft -copyleft = "warn" +copyleft = "deny" # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses # * both - The license will be approved if it is both OSI-approved *AND* FSF # * either - The license will be approved if it is either OSI-approved *OR* FSF @@ -117,7 +118,23 @@ exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list - #{ allow = ["Zlib"], name = "adler32", version = "*" }, + + + # "Reciprocal" licensed crate pulled directly from crates.io without modifications + # Important: Update https://third-party-mirror.googlesource.com/webpki-roots/ if you update this version + { allow = ["MPL-2.0"], name = "webpki-roots", version = "0.25.2" }, + + # "Reciprocal" licensed crate pulled directly from crates.io without modifications + # Important: Update https://third-party-mirror.googlesource.com/option-ext/ if you update this version + { allow = ["MPL-2.0"], name = "option-ext", version = "0.2.0" }, + + # "Reciprocal" licensed crate pulled directly from crates.io without modifications + # Important: Update https://third-party-mirror.googlesource.com/smartstring/ if you update this version + { allow = ["MPL-2.0"], name = "smartstring", version = "1.0.1" }, + + # "Reciprocal" licensed crate pulled directly from crates.io without modifications + # Important: Update https://third-party-mirror.googlesource.com/cbindgen/ if you update this version + { allow = ["MPL-2.0"], name = "cbindgen", version = "0.26.0" }, ] # Some crates don't have (easily) machine readable licensing information,
diff --git a/nearby/presence/CMakeLists.txt b/nearby/presence/CMakeLists.txt index 630d172..bb099de 100644 --- a/nearby/presence/CMakeLists.txt +++ b/nearby/presence/CMakeLists.txt
@@ -67,7 +67,7 @@ if (ENABLE_FUZZ) if (NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") MESSAGE(FATAL_ERROR "fuzzing is only enabed when building with Clang, please set CC and CXX to use clang instead of ${CMAKE_CXX_COMPILER_ID}") - endif() + endif () add_subdirectory(${THIRD_PARTY_DIR}/boringssl boringssl-build) add_subdirectory(${THIRD_PARTY_DIR}/fuzztest fuzztest-build) @@ -83,9 +83,13 @@ set_directory_properties( PROPERTIES COMPILE_OPTIONS - -Wall -Wextra -Wimplicit-fallthrough -Wextra-semi - -Wno-missing-field-initializers -Wno-unused-parameter -Wno-psabi - -Wshadow -Wsign-compare + -Werror + -Wall + -Wextra + -Wimplicit-fallthrough + -Wextra-semi + -Wshadow + -Wsign-compare ) endif ()
diff --git a/nearby/presence/array_view/src/lib.rs b/nearby/presence/array_view/src/lib.rs index e2ea8d4..d4d7c84 100644 --- a/nearby/presence/array_view/src/lib.rs +++ b/nearby/presence/array_view/src/lib.rs
@@ -62,7 +62,7 @@ } } - /// Returns the prefix of the array as a slice. + /// Returns the occupied portion of the array as a slice. pub fn as_slice(&self) -> &[T] { &self.array[..self.len] } @@ -105,9 +105,8 @@ } #[cfg(test)] +#[allow(clippy::unwrap_used)] mod tests { - #![allow(clippy::unwrap_used)] - extern crate std; use crate::ArrayView; use std::format;
diff --git a/nearby/presence/ldt/benches/ldt_scan.rs b/nearby/presence/ldt/benches/ldt_scan.rs index b1711ad..f5fa359 100644 --- a/nearby/presence/ldt/benches/ldt_scan.rs +++ b/nearby/presence/ldt/benches/ldt_scan.rs
@@ -19,7 +19,8 @@ use crypto_provider_rustcrypto::RustCrypto; use ctr::cipher::{KeyIvInit as _, StreamCipher as _, StreamCipherSeek as _}; use ldt::{ - DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Padder, Swap, XorPadder, + DefaultPadder, LdtCipher, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Padder, Swap, + XorPadder, }; use ldt_tbc::TweakableBlockCipher; use sha2::Digest as _; @@ -159,7 +160,9 @@ } trait ScanCipher { + #[allow(dead_code)] fn encrypt(&mut self, buf: &mut [u8]); + fn decrypt(&mut self, buf: &mut [u8]); }
diff --git a/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs b/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs index 7e7c943..43ba617 100644 --- a/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs +++ b/nearby/presence/ldt/examples/gen_ldt_xor_pad_test_vectors.rs
@@ -19,7 +19,7 @@ use crypto_provider::aes::BLOCK_SIZE; use crypto_provider::{aes, CryptoProvider, CryptoRng}; use crypto_provider_rustcrypto::RustCrypto; -use ldt::{LdtEncryptCipher, LdtKey, Swap, XorPadder}; +use ldt::{LdtCipher, LdtEncryptCipher, LdtKey, Swap, XorPadder}; use rand::{Rng as _, SeedableRng as _}; use rand_ext::*; use serde_json::json;
diff --git a/nearby/presence/ldt/examples/ldt_benchmark.rs b/nearby/presence/ldt/examples/ldt_benchmark.rs index 101e17b..a710d56 100644 --- a/nearby/presence/ldt/examples/ldt_benchmark.rs +++ b/nearby/presence/ldt/examples/ldt_benchmark.rs
@@ -18,7 +18,7 @@ use clap::Parser as _; use crypto_provider_rustcrypto::RustCrypto; -use ldt::{LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Swap, XorPadder}; +use ldt::{LdtCipher, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Mix, Swap, XorPadder}; use crypto_provider::{CryptoProvider, CryptoRng}; use ldt_tbc::TweakableBlockCipher;
diff --git a/nearby/presence/ldt/examples/ldt_prp.rs b/nearby/presence/ldt/examples/ldt_prp.rs index 7734952..fea1904 100644 --- a/nearby/presence/ldt/examples/ldt_prp.rs +++ b/nearby/presence/ldt/examples/ldt_prp.rs
@@ -23,7 +23,7 @@ #![allow(clippy::unwrap_used, clippy::indexing_slicing)] -use clap::{self, Parser as _}; +use clap::Parser as _; use crypto_provider::aes::BLOCK_SIZE; use crypto_provider::{CryptoProvider, CryptoRng}; use crypto_provider_rustcrypto::RustCrypto;
diff --git a/nearby/presence/ldt/fuzz/Cargo.toml b/nearby/presence/ldt/fuzz/Cargo.toml index 3f37e98..c192792 100644 --- a/nearby/presence/ldt/fuzz/Cargo.toml +++ b/nearby/presence/ldt/fuzz/Cargo.toml
@@ -1,32 +1,23 @@ [package] name = "ldt-fuzz" -version = "0.0.0" -authors = ["Automatically generated"] -publish = false -edition = "2018" +version.workspace = true +publish.workspace = true +edition.workspace = true [package.metadata] cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4" -arbitrary = { version = "1.1.7", features = ["derive"] } +arbitrary = { workspace = true, features = ["derive"] } +crypto_provider_rustcrypto.workspace = true +derive_fuzztest.workspace = true +ldt.workspace = true +xts_aes.workspace = true -[dependencies.ldt] -path = ".." - -[dependencies.xts_aes] -path = "../../xts_aes" - -[dependencies.crypto_provider_rustcrypto] -path = "../../../crypto/crypto_provider_rustcrypto" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true [[bin]] -name = "ldt-roundtrip" -path = "fuzz_targets/ldt_roundtrip.rs" -test = false +name = "ldt_roundtrip" +path = "src/bin/ldt_roundtrip.rs" doc = false
diff --git a/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs b/nearby/presence/ldt/fuzz/src/bin/ldt_roundtrip.rs similarity index 69% rename from nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs rename to nearby/presence/ldt/fuzz/src/bin/ldt_roundtrip.rs index 13e2a46..097900f 100644 --- a/nearby/presence/ldt/fuzz/fuzz_targets/ldt_roundtrip.rs +++ b/nearby/presence/ldt/fuzz/src/bin/ldt_roundtrip.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,25 +14,28 @@ // limitations under the License. use crypto_provider_rustcrypto::RustCrypto; +use derive_fuzztest::fuzztest; use ldt::*; -use libfuzzer_sys::fuzz_target; use xts_aes::XtsAes128; -fuzz_target!(|data: LdtFuzzInput| { - let ldt_enc = - LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&data.ldt_key)); - let ldt_dec = - LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&LdtKey::from_concatenated(&data.ldt_key)); +#[fuzztest] +fn test(data: LdtFuzzInput) { + let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new( + &LdtKey::from_concatenated(&data.ldt_key), + ); + let ldt_dec = LdtDecryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new( + &LdtKey::from_concatenated(&data.ldt_key), + ); let len = 16 + (data.len as usize % 16); - let padder: XorPadder<16> = data.xor_padder.clone().into(); + let padder: XorPadder<16> = data.xor_padder.into(); - let mut buffer = data.plaintext.clone(); + let mut buffer = data.plaintext; ldt_enc.encrypt(&mut buffer[..len], &padder).unwrap(); ldt_dec.decrypt(&mut buffer[..len], &padder).unwrap(); assert_eq!(data.plaintext, buffer); -}); +} -#[derive(Debug, arbitrary::Arbitrary)] +#[derive(Clone, Debug, arbitrary::Arbitrary)] struct LdtFuzzInput { // XTS-AES128 keys ldt_key: [u8; 64],
diff --git a/nearby/presence/ldt/src/lib.rs b/nearby/presence/ldt/src/lib.rs index 8596ad2..2b4a962 100644 --- a/nearby/presence/ldt/src/lib.rs +++ b/nearby/presence/ldt/src/lib.rs
@@ -19,11 +19,20 @@ #[cfg(feature = "std")] extern crate std; -use core::{fmt, marker::PhantomData}; +use core::{fmt, marker::PhantomData, ops}; use crypto_provider::CryptoProvider; use ldt_tbc::{ConcatenatedKeyArray, TweakableBlockCipher, TweakableBlockCipherKey}; use ldt_tbc::{TweakableBlockCipherDecrypter, TweakableBlockCipherEncrypter}; +/// Common functionality for [LdtEncryptCipher] and [LdtDecryptCipher] +pub trait LdtCipher<const B: usize, T: TweakableBlockCipher<B>> { + /// The range of input lengths the cipher can operate on + const VALID_INPUT_LEN: ops::Range<usize>; + + /// Create a new cipher with the provided [TweakableBlockCipher] and [Mix] function + fn new(key: &LdtKey<T::Key>) -> Self; +} + /// Implementation of the [LDT](https://eprint.iacr.org/2017/841.pdf) length doubler encryption cipher. /// /// `B` is the block size. @@ -36,16 +45,21 @@ mix_phantom: PhantomData<M>, } -impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtEncryptCipher<B, T, M> { - /// Create an [LdtEncryptCipher] with the provided Tweakable block cipher and Mix function - pub fn new(key: &LdtKey<T::Key>) -> Self { +impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtCipher<B, T> + for LdtEncryptCipher<B, T, M> +{ + const VALID_INPUT_LEN: ops::Range<usize> = input_len_range::<B>(); + + fn new(key: &LdtKey<T::Key>) -> Self { LdtEncryptCipher { cipher_1: T::EncryptionCipher::new(&key.key_1), cipher_2: T::EncryptionCipher::new(&key.key_2), mix_phantom: PhantomData, } } +} +impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtEncryptCipher<B, T, M> { /// Encrypt `data` in place, performing the pad operation with `padder`. /// /// Unless you have particular padding needs, use [DefaultPadder]. @@ -79,13 +93,6 @@ impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtDecryptCipher<B, T, M> { /// Create an [LdtDecryptCipher] with the provided Tweakable block cipher and Mix function - pub fn new(key: &LdtKey<T::Key>) -> Self { - LdtDecryptCipher { - cipher_1: T::DecryptionCipher::new(&key.key_1), - cipher_2: T::DecryptionCipher::new(&key.key_2), - mix_phantom: PhantomData, - } - } /// Decrypt `data` in place, performing the pad operation with `padder`. /// @@ -106,6 +113,26 @@ } } +impl<const B: usize, T: TweakableBlockCipher<B>, M: Mix> LdtCipher<B, T> + for LdtDecryptCipher<B, T, M> +{ + const VALID_INPUT_LEN: ops::Range<usize> = input_len_range::<B>(); + + fn new(key: &LdtKey<T::Key>) -> Self { + LdtDecryptCipher { + cipher_1: T::DecryptionCipher::new(&key.key_1), + cipher_2: T::DecryptionCipher::new(&key.key_2), + mix_phantom: PhantomData, + } + } +} + +/// Returns the range of valid input lengths to encrypt or decrypt with LDT for a given tweakable +/// block cipher block size `B`, namely `[B, B * 2)`. +const fn input_len_range<const B: usize>() -> ops::Range<usize> { + B..B * 2 +} + // internal implementation of ldt cipher operations, re-used by encryption and decryption, by providing // the corresponding cipher_op and mix operation fn do_ldt<const B: usize, T, O, C, X, P>( @@ -124,7 +151,7 @@ X: for<'a, 'b> Fn(&'a [u8], &'b [u8]) -> (&'b [u8], &'a [u8]), P: Padder<B, T>, { - if data.len() < B || data.len() >= B * 2 { + if !input_len_range::<B>().contains(&data.len()) { return Err(LdtError::InvalidLength(data.len())); } let s = data.len() - B; @@ -229,6 +256,7 @@ /// Per section 2.4, swapping `a` and `b` is a valid mix function pub struct Swap {} + impl Mix for Swap { fn forwards<'a, 'b>(a: &'a [u8], b: &'b [u8]) -> (&'b [u8], &'a [u8]) { debug_assert_eq!(a.len(), b.len());
diff --git a/nearby/presence/ldt/tests/ldt_roundtrip.rs b/nearby/presence/ldt/tests/ldt_roundtrip.rs index 251cefe..fabddf0 100644 --- a/nearby/presence/ldt/tests/ldt_roundtrip.rs +++ b/nearby/presence/ldt/tests/ldt_roundtrip.rs
@@ -20,7 +20,7 @@ use ldt::*; use ldt_tbc::TweakableBlockCipher; use rand::rngs::StdRng; -use rand::{self, distributions, Rng as _, SeedableRng as _}; +use rand::{distributions, Rng as _, SeedableRng as _}; use rand_ext::{random_bytes, random_vec}; use xts_aes::{XtsAes128, XtsAes256}; @@ -57,9 +57,7 @@ fn roundtrip_xor_padder() { let mut rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); let mut rc_rng = rand::rngs::StdRng::from_entropy(); - // 2 bytes smaller because we're using a 2 byte salt - let plaintext_len_range = - distributions::Uniform::new_inclusive(BLOCK_SIZE, BLOCK_SIZE * 2 - 1 - 2); + let plaintext_len_range = distributions::Uniform::new_inclusive(BLOCK_SIZE, BLOCK_SIZE * 2 - 1); for _ in 0..100_000 { let padder: XorPadder<BLOCK_SIZE> =
diff --git a/nearby/presence/ldt/tests/ldt_test_vectors.rs b/nearby/presence/ldt/tests/ldt_test_vectors.rs index 03b5d3f..1e8a5e1 100644 --- a/nearby/presence/ldt/tests/ldt_test_vectors.rs +++ b/nearby/presence/ldt/tests/ldt_test_vectors.rs
@@ -16,7 +16,7 @@ use anyhow::anyhow; use crypto_provider_default::CryptoProviderImpl; -use ldt::{DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Swap, XorPadder}; +use ldt::{DefaultPadder, LdtCipher, LdtDecryptCipher, LdtEncryptCipher, LdtKey, Swap, XorPadder}; use std::{fs, io::Read as _}; use test_helper::{extract_key_array, extract_key_vec}; use xts_aes::XtsAes128;
diff --git a/nearby/presence/ldt/tests/tests.rs b/nearby/presence/ldt/tests/tests.rs index 25938fb..e68273f 100644 --- a/nearby/presence/ldt/tests/tests.rs +++ b/nearby/presence/ldt/tests/tests.rs
@@ -18,7 +18,8 @@ use crypto_provider::aes::BLOCK_SIZE; use crypto_provider_default::CryptoProviderImpl; use ldt::{ - DefaultPadder, LdtDecryptCipher, LdtEncryptCipher, LdtError, LdtKey, Padder, Swap, XorPadder, + DefaultPadder, LdtCipher, LdtDecryptCipher, LdtEncryptCipher, LdtError, LdtKey, Padder, Swap, + XorPadder, }; use xts_aes::{XtsAes128, XtsAes128Key}; @@ -137,20 +138,22 @@ #[test] fn encrypt_too_short_err() { - do_length_check_enc(7) + do_length_check_enc(15) } #[test] fn encrypt_too_long_err() { - do_length_check_enc(40) + do_length_check_enc(32) } + #[test] fn decrypt_too_short_err() { - do_length_check_dec(7) + do_length_check_dec(15) } + #[test] fn decrypt_too_long_err() { - do_length_check_dec(40) + do_length_check_dec(32) } fn do_length_check_dec(len: usize) {
diff --git a/nearby/presence/ldt_np_adv/Cargo.toml b/nearby/presence/ldt_np_adv/Cargo.toml index ce84505..5d18a28 100644 --- a/nearby/presence/ldt_np_adv/Cargo.toml +++ b/nearby/presence/ldt_np_adv/Cargo.toml
@@ -23,6 +23,7 @@ crypto_provider_default = { workspace = true, features = ["rustcrypto", "std"] } rand_ext.workspace = true test_helper.workspace = true +test_vector_hkdf.workspace = true rand.workspace = true base64.workspace = true
diff --git a/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs index b8de6fd..f9b1880 100644 --- a/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs +++ b/nearby/presence/ldt_np_adv/benches/ldt_adv_scan.rs
@@ -36,7 +36,7 @@ let payload_len = rng.gen_range(crypto_provider::aes::BLOCK_SIZE..=LDT_XTS_AES_MAX_LEN); let payload = random_vec(&mut rng, payload_len); - let salt = LegacySalt::from(rng.gen::<[u8; 2]>()); + let salt = V0Salt::from(rng.gen::<[u8; 2]>()); #[allow(clippy::unit_arg)] b.iter(|| { let ciphers = build_ciphers(&configs); @@ -48,7 +48,7 @@ let payload_len = rng.gen_range(crypto_provider::aes::BLOCK_SIZE..=LDT_XTS_AES_MAX_LEN); let payload = random_vec(&mut rng, payload_len); - let salt = LegacySalt::from(rng.gen::<[u8; 2]>()); + let salt = V0Salt::from(rng.gen::<[u8; 2]>()); let ciphers = build_ciphers(&configs); #[allow(clippy::unit_arg)] b.iter(|| black_box(find_matching_item::<C>(&ciphers, salt, &payload))); @@ -60,11 +60,11 @@ criterion_main!(benches); fn find_matching_item<C: CryptoProvider>( - ciphers: &[LdtNpAdvDecrypterXtsAes128<C>], - salt: LegacySalt, + ciphers: &[AuthenticatedNpLdtDecryptCipher<C>], + salt: V0Salt, payload: &[u8], ) { - let padder = salt_padder::<16, C>(salt); + let padder = salt_padder::<C>(salt); let _ = ciphers .iter() .enumerate() @@ -75,12 +75,12 @@ .ok() }) .next() - .map(|(index, buffer)| MatchResult { matching_index: index, buffer }); + .map(|(index, (token, plaintext))| MatchResult { matching_index: index, token, plaintext }); } fn build_ciphers<C: CryptoProvider>( configs: &[CipherConfig<C>], -) -> Vec<LdtNpAdvDecrypterXtsAes128<C>> { +) -> Vec<AuthenticatedNpLdtDecryptCipher<C>> { configs .iter() .map(|config| { @@ -99,8 +99,10 @@ pub struct MatchResult<const O: usize> { /// The index of the batch item that matched matching_index: usize, - /// The buffer holding the plaintext - buffer: ArrayView<u8, O>, + /// The matched identity token + token: V0IdentityToken, + /// The buffer holding the remaining plaintext + plaintext: ArrayView<u8, O>, } fn random_configs<C: CryptoProvider, R: rand::Rng>(
diff --git a/nearby/presence/ldt_np_adv/fuzz/Cargo.toml b/nearby/presence/ldt_np_adv/fuzz/Cargo.toml index a346c6b..e4f497c 100644 --- a/nearby/presence/ldt_np_adv/fuzz/Cargo.toml +++ b/nearby/presence/ldt_np_adv/fuzz/Cargo.toml
@@ -1,40 +1,30 @@ [package] name = "ldt-np-adv-fuzz" -version = "0.0.0" -authors = ["Automatically generated"] -publish = false -edition = "2018" +version.workspace = true +publish.workspace = true +edition.workspace = true [package.metadata] cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4" -arbitrary = { version = "1.1.7", features = ["derive"] } -crypto_provider_rustcrypto = { path = "../../../crypto/crypto_provider_rustcrypto", features = ["alloc"] } +arbitrary = { workspace = true, features = ["derive"] } +crypto_provider_rustcrypto = { workspace = true, features = ["alloc"] } +derive_fuzztest.workspace = true +ldt.workspace = true +ldt_np_adv.workspace = true +np_hkdf.workspace = true +xts_aes.workspace = true -[dependencies.ldt_np_adv] -path = ".." - -[dependencies.np_hkdf] -path = "../../np_hkdf" -[dependencies.xts_aes] -path = "../../xts_aes" -[dependencies.ldt] -path = "../../ldt" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true [[bin]] -name = "ldt-np-roundtrip" -path = "fuzz_targets/ldt_np_roundtrip.rs" -test = false +name = "ldt_np_roundtrip" +path = "src/bin/ldt_np_roundtrip.rs" doc = false [[bin]] -name = "ldt-np-decrypt" -path = "fuzz_targets/ldt_np_decrypt.rs" -test = false +name = "ldt_np_decrypt" +path = "src/bin/ldt_np_decrypt.rs" doc = false
diff --git a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs b/nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_decrypt.rs similarity index 82% rename from nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs rename to nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_decrypt.rs index 2039219..995ac15 100644 --- a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_decrypt.rs +++ b/nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_decrypt.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,26 +14,25 @@ // limitations under the License. use crypto_provider_rustcrypto::RustCrypto; +use derive_fuzztest::fuzztest; use ldt_np_adv::*; -use libfuzzer_sys::fuzz_target; -fuzz_target!(|data: LdtNpDecryptFuzzInput| { +#[fuzztest] +fn test(data: LdtNpDecryptFuzzInput) { // try to decrypt data that won't pass validation let salt = data.salt.into(); - let padder = salt_padder::<16, RustCrypto>(salt); + let padder = salt_padder::<RustCrypto>(salt); let hkdf = np_hkdf::NpKeySeedHkdf::<RustCrypto>::new(&data.key_seed); let cipher = build_np_adv_decrypter_from_key_seed::<RustCrypto>(&hkdf, data.metadata_key_hmac); let len = 16 + (data.len as usize % 16); let ciphertext = data.ciphertext; - let err = cipher - .decrypt_and_verify(&ciphertext[..len], &padder) - .unwrap_err(); + let err = cipher.decrypt_and_verify(&ciphertext[..len], &padder).unwrap_err(); assert_eq!(LdtAdvDecryptError::MacMismatch, err); -}); +} -#[derive(Debug, arbitrary::Arbitrary)] +#[derive(Clone, Debug, arbitrary::Arbitrary)] struct LdtNpDecryptFuzzInput { key_seed: [u8; 32], salt: [u8; 2],
diff --git a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs b/nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_roundtrip.rs similarity index 68% rename from nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs rename to nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_roundtrip.rs index 69f82c3..27ee8aa 100644 --- a/nearby/presence/ldt_np_adv/fuzz/fuzz_targets/ldt_np_roundtrip.rs +++ b/nearby/presence/ldt_np_adv/fuzz/src/bin/ldt_np_roundtrip.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,35 +14,34 @@ // limitations under the License. use crypto_provider_rustcrypto::RustCrypto; +use derive_fuzztest::fuzztest; use ldt::*; use ldt_np_adv::*; -use libfuzzer_sys::fuzz_target; use xts_aes::XtsAes128; -fuzz_target!(|data: LdtNpRoundtripFuzzInput| { +#[fuzztest] +fn test(data: LdtNpRoundtripFuzzInput) { let salt = data.salt.into(); - let padder = salt_padder::<16, RustCrypto>(salt); + let padder = salt_padder::<RustCrypto>(salt); let hkdf = np_hkdf::NpKeySeedHkdf::<RustCrypto>::new(&data.key_seed); - let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&hkdf.legacy_ldt_key()); - let metadata_key_hmac: [u8; 32] = hkdf - .legacy_metadata_key_hmac_key() - .calculate_hmac(&data.plaintext[..14]); + let ldt_enc = LdtEncryptCipher::<16, XtsAes128<RustCrypto>, Swap>::new(&hkdf.v0_ldt_key()); + let identity_token_hmac: [u8; 32] = + hkdf.v0_identity_token_hmac_key().calculate_hmac::<RustCrypto>(&data.plaintext[..14]); - let cipher = build_np_adv_decrypter_from_key_seed::<RustCrypto>(&hkdf, metadata_key_hmac); + let cipher = build_np_adv_decrypter_from_key_seed::<RustCrypto>(&hkdf, identity_token_hmac); let len = 16 + (data.len as usize % 16); let mut ciphertext = data.plaintext; ldt_enc.encrypt(&mut ciphertext[..len], &padder).unwrap(); - let plaintext = cipher - .decrypt_and_verify(&ciphertext[..len], &padder) - .unwrap(); + let (token, plaintext) = cipher.decrypt_and_verify(&ciphertext[..len], &padder).unwrap(); - assert_eq!(&data.plaintext[..len], plaintext.as_slice()); -}); + assert_eq!(&data.plaintext[..14], token.as_slice()); + assert_eq!(&data.plaintext[14..len], plaintext.as_slice()); +} -#[derive(Debug, arbitrary::Arbitrary)] +#[derive(Clone, Debug, arbitrary::Arbitrary)] struct LdtNpRoundtripFuzzInput { key_seed: [u8; 32], salt: [u8; 2],
diff --git a/nearby/presence/ldt_np_adv/resources/test/np_adv_test_vectors.json b/nearby/presence/ldt_np_adv/resources/test/np_adv_test_vectors.json index f93ed7d..9c038f6 100644 --- a/nearby/presence/ldt_np_adv/resources/test/np_adv_test_vectors.json +++ b/nearby/presence/ldt_np_adv/resources/test/np_adv_test_vectors.json
@@ -1,9002 +1,902 @@ [ { - "key_seed": "CCDB2489E9FCAC42B39348B8941ED19A1D360E75E098C8C15E6B1CC2B620CD39", - "ldt_key": "2E5F784296A2ECBB93D7D6E691541F610D6559D5A71903DD80E9FC84659DCAD60687E41330962A9499268ACE1F57857E35220D25B6AD795F9AEDC1A98D948937", - "hmac_key": "CAEF6DF5857EB67D8D3904D28AF752DCD3115C3CD7C37ECC5076ACE2FAEA5931", - "adv_salt": "32EE", - "plaintext": "CD683FE1A1D1F846543D0A13D4AEA40040C8D67B", - "ciphertext": "04344411F1E57C841FE0F7150636BC782455059A", - "metadata_key_hmac": "DFB90A1F9B1FE28D18BBCCA52240B5CC2CCB5F8D5289A3CB64EB3541CA614BB4" + "adv_salt": "837A", + "ciphertext": "A3D54A03A1464A5D99ECE37D911D52B4E947D4089A", + "hmac_key": "BE092602F20D6B4EC33E2B9AEF678C2B023EA9FAB898301BEC13C38FDBFBDFF9", + "identity_token_hmac": "D93A08B8D832EA27B73E7E968A91B6C81B0DBBD4FC78296A69F47D022B64B08E", + "key_seed": "B79F74DE4ED9D43E3FF020A41E977AD5A323E42CA0BE566CB760E020B375840A", + "ldt_key": "5EEA9AC9AD55DDA8AF8E9C58A2A0755C3F14FC1A64B1EEAF7685F414841570A3218AD128B5BA7854ABA0F57F0D0ABE8A49A735EB6FC71761D8230C4B05FFFB39", + "plaintext": "240F027310713775CC527734711817A03BEB8E56A2" }, { - "key_seed": "7673D9F05DB9AEA7C7C794A24AEF8275384CECB1149B24B9150F56FAF35E3738", - "ldt_key": "BC059EC24647A31ABA5FA99A6254868E422D26478F5D5D3BE65802D04353ECD1FF8FE74F36F7CB58FFC2DE87CEF1739E6EF6D64B3BB592F49BEEE2EBDE83F673", - "hmac_key": "B78D559004B09975C2F52F5CACD5D4531A24AADE730E1B37E01BF8DD7D5AFA92", - "adv_salt": "E578", - "plaintext": "4306ECBADD6023CAA503600AC716EBDFC97EC8333D1CDC1FF91A76", - "ciphertext": "877672F5A7AE17B57DADC197A8EC2D20F7BF14472AE73E8842A0C1", - "metadata_key_hmac": "62DE26DA7D947434D0C371205398FB2A1B960B34AE226ED73AA118AD7016AF73" + "adv_salt": "96A6", + "ciphertext": "44C8C117FE2D5586022C937EF257D5C4044BFACD7BA9E87B40", + "hmac_key": "139AF9A6201E31A30F7FEE1F30611D38E972E9D184A1FCDD44BDCE63CD9AB49C", + "identity_token_hmac": "A36DCAE0D2A6653B48D3F5011575E9068125B1DF6C881E3BC7DB6B159EA72CB5", + "key_seed": "B500DA3B332D2479A6D8DB6E7D15ABF6B4FF4B904BE5F80AFAE122195A799FAB", + "ldt_key": "45C63D99AC38E54FB4FDB53DC596B454D76CEF966B599C27419F4819FC9810CD87312C979C48ED6B83C53125C9EF55192458BF679541E9861E8E49A5FA6BAF6E", + "plaintext": "5403F6847243EFA04FC14888589736F0A5679472ACB8B13E9D" }, { - "key_seed": "A07E28586F397D9C8D2EBF5E8236647FDB887D15772BC7E3C0C85FC7754F5C4D", - "ldt_key": "EBB039B779FF16AC0AF67D799B882107A694F689F19CB85E1C847CA34A58344A3581D059BDB0F0A7A0C34D19539E45215F4CBAE183B9047B34A347CBD3017F1F", - "hmac_key": "AE83401E6174D5F087EFDB1E0FBB7D77808BE24CD708F3180036BBA298C76268", - "adv_salt": "4D27", - "plaintext": "EF34E725EDA3C6069C9B63C5E8000C3ACA9A027E", - "ciphertext": "33466B24B8137296608257C97EC181F1EB574F04", - "metadata_key_hmac": "5EA6CB73502B1419F1BC85D04E73EC72889635F972C8C221FDB0F0EC1CAF09CF" + "adv_salt": "07B6", + "ciphertext": "E319FCF0BB99BBFC0777A05AB272EADC7F0E821AF8C338", + "hmac_key": "38E785461FF16DF3B7863F0F96B9D74B83F2A8525FA6A4A2F1DB3221EDD9F3BE", + "identity_token_hmac": "B1725BEEE1B8C61FD200FB13BE3585F39F9EECF6DD31E35C0133619B56ED048B", + "key_seed": "A077F988C1B6EA01E5D963A4E2A20D80FD488004E38883EADE3718227002FE71", + "ldt_key": "E2CC5F34FC7CF7B12D2A79ACFC59EA4BB129BDA2D56F538C4932A890A814567991FC5187ACFCC520744AB24DBCB30076D71E5B2A9F412F040D6BBCD20B0C758E", + "plaintext": "9745E73B23263894A11B0C1AB144CDDE85EF145BA18CAF" }, { - "key_seed": "71F35AB829BB1E2F7BDA59A65BE55741F7FC87BBDE81D6B10D85CB6557DC47AC", - "ldt_key": "5960D8FED51947B2ED92B3F268DB6641A508629E747923B91F67C3F8426895ACAD3800AAA2F72D4EA3D26D1C620D2D8EFDAFAD7CAB0516F0DE82D1C8E5C0826A", - "hmac_key": "3E14DEF966F921D933E3625A8C11AC4544D5A8A7882F53C67BAF9243DD1F7B2F", - "adv_salt": "4330", - "plaintext": "F46197691BD5D241DEC41D8CE7B4B58A932446DCD3", - "ciphertext": "57642D5ACAFCA0DAD6B1DF1BEDBF11D3282CD1B822", - "metadata_key_hmac": "ACB7C8AE37F526CD581783E63043A48FF823B094D0AA5E6311FEBFC4D8F57CC2" + "adv_salt": "B673", + "ciphertext": "D788023D9DA9237C2DDED0AAE3BFAD1DF9D1EB2641B3426776C5", + "hmac_key": "69C7E2FBEEF2D39029CD4C12B38F8BE0531766EFF1C9D8D341E0177F7708B7B5", + "identity_token_hmac": "D63CA07B22D9FE3D0F3FCF5A0924D73F21646215F366F6555BCD230B5990E2FB", + "key_seed": "1255F9C1EF194FF42AA4D890AE745CE4944D18F4E6F52672E808FA77CDB5149F", + "ldt_key": "A21D10CEF0130B8F6CAEF9A3BA2D6549440D008D9112A4289AAA128CD9E0536DE643AA593A485A898EC7113853ECDFC283DEA363C8AEE35DAC38DC77233FAF02", + "plaintext": "5C0EF76123617A69862568D1B3822767AF785A37D4834D7CA4F6" }, { - "key_seed": "8A5DD2068ADD99ABF9FF0020A1728AAA51DE020711BC6825D034764CD622E0DA", - "ldt_key": "2698F62A3F4AC3CC2A47E779BB9C11C1C56ED1C47B2BDC3DC4A1607B91C02472D2BDEE84359CB7E8DF1539CBF87772374E4DA14B2D860FCD581780CB5E86E410", - "hmac_key": "350C4F03B87A73C299D4875776CDAAFA4BD62BF0FF671A8DEB624844B413B1EA", - "adv_salt": "87C9", - "plaintext": "2FBFE59B984F78E52858AA5F954302FA039A17DC9B", - "ciphertext": "045CB170393A527E4C27BCF5F0B5CC1C8ACA416A62", - "metadata_key_hmac": "549162023841BF6155AFB443FB966C4173982D736ACC036E4EAFF0934806853B" + "adv_salt": "1C75", + "ciphertext": "2AE1434E1D7E5B3F8F472E2CF8B2534CFF2A1B9A12", + "hmac_key": "10F332744FCFC9703953BA2F85C33CE1EA943E45FF43A48C78BE7FECBD34E338", + "identity_token_hmac": "D8BA9FF93E085E6929DE053FF5E297DD75B152ACB8AA9B44097331FE43BFB383", + "key_seed": "6249B433AD883CC6749400BAC62FD94AF309D2FAA3F0906E7AF2743B09E842F7", + "ldt_key": "DD7AFE6BB2C1216B81257E09E1E7C06E65A63B9C24A3AC1A5472B79CF264DB986381B58BE21BE91FCB55A40F74A563E50D65768603574E7778663528109ACEDE", + "plaintext": "9C0407828591BC9853079B1054D2A10C606572E71B" }, { - "key_seed": "7E100C7A639AEBCA822893923FFE2D8F27A7F2488FE0A5BCC7275B3A02EA4F03", - "ldt_key": "09119B7782E29A680A068AC19D469315E4381A063FBE8FE921BB20EC6C845E883CCA820D159C824194E53281E5228B1C3438A64B8DBADFD1E514397E4AC877C8", - "hmac_key": "69A75B56EEAFEB03334758B127DD700E4A40517C4C6F9D2C43E35B9948615807", - "adv_salt": "A2D2", - "plaintext": "AC3A74E6D924FF68ED4EFB0CC6C5E78F", - "ciphertext": "15707F19DDB011093048FA78B5411CAD", - "metadata_key_hmac": "25100413FD7F97F99F5E266A7B240AC5F77C9009D52E488D07B08665BE97C4F9" + "adv_salt": "51B7", + "ciphertext": "F66B47B187370914A59EE09EAEE4316E932B", + "hmac_key": "1B6460F0A60C325D5DE22E82EF4D002C6A323B6181CC3837B7A934CCCEA0EA53", + "identity_token_hmac": "F611A97D2914DAF39110CF9456CB281A384FF5C62DEA8416F45F49A464F726DB", + "key_seed": "777D1B46773DD5BA813A18AA35EDC68DD3D745C09FC265EB9C576B66C0C45168", + "ldt_key": "EFA36B82D474732A8CDA1A1388B8AF2C49CD1B1A5EBA2966BE98BCAFBF86F265CEA44C1F7AD32DB2C9DFFD58D2E7E2B377644B3DF806E180ADAAA1B98AC24247", + "plaintext": "B4F9CC4D7AFA0805B9AF2D196F690C1622B3" }, { - "key_seed": "B109A2FD9FCC6ED5F0E4AC288C13C7D2A019CF1C3E74015B2B72BFE412FF2205", - "ldt_key": "313B0D71CFC77E9B6F5D504473C0C2449B8AC600D0B0A8E138B24C4AC25293BDA7C061B39529DF9FFC8DB8B0924D6426E4ABFBC198E0D7B0B95F6B6EC1EED9DD", - "hmac_key": "E06EFB927FA2EAEABF0ADD366231BE98A798232E117AAB23A43B7093C4F0B758", - "adv_salt": "A39F", - "plaintext": "34FCEE9C0B0D3DFB623FD68221220EAB", - "ciphertext": "AF802195A59AF7DC3675757026789B67", - "metadata_key_hmac": "D16684237542761E91538996F8C9F732D9E4CC2BF2E0641514C004048E2246FE" + "adv_salt": "75FB", + "ciphertext": "7778EE076A15789D61B2BBA7B70A7AD47AE2", + "hmac_key": "C7D207E1C26E848C1E06AA795504A9CFB7B19E1F6941924405A110AD9F600487", + "identity_token_hmac": "DBDF585FB25FBBF5577B43718F750D2DE0624835FB0C04D1E994DB0AE168EFE1", + "key_seed": "2E4D649C4150E4BBBE5257EDF4EB7D822F294B1545E636174D5FA9130166D9C9", + "ldt_key": "E83DFA126AA19B06E93F9DE23BF9B5E900E8179318E6D82F2C3F9A29C306DAAD280C8780DDFC28F0AD2C21D95342488771778C31FFB27D86A73CEC71928B5B66", + "plaintext": "CD6CC0B8FBB7A945D6CC1251C41BBF78B09A" }, { - "key_seed": "7650C00799B0B33334FD2328E66632159F0510C206D9476CD7457B88449AD908", - "ldt_key": "AEDA9657903EC6D5258CF7EE66853B9AC85962B7D2F9429A2B09013C6FF5C9B1931F73875822E027913F0BD0D00E73086193040A108958A66136528945DB05F1", - "hmac_key": "8A4660095102A7727A50E6809C2FBE0AF359003F68E47D9CFA3AA7D4B8C1CD5B", - "adv_salt": "7127", - "plaintext": "E8E00B596CA5207090D29EABA3336F77EDC9916AB5D325A2BB798CFB79", - "ciphertext": "94F71B56EBD8CF9829285FA6282C2A4FA781D1F060B7E46064EDB9F00E", - "metadata_key_hmac": "545549A7AD83A0D60D5031E371BA1F90235606CE3C8C21469FAF2FA06147D112" + "adv_salt": "6B06", + "ciphertext": "5D19BEE1FEFC66260CB85107F192824DEB52BD887A5B", + "hmac_key": "8B4CB5A132FE3FA569ADCF4E6D3544FF87D9A3685672822A4155E4C5541C477F", + "identity_token_hmac": "87F4AF538B304AB7423E7C6DE66986CB0E3B0627288B12B5B6DCFE158A77102C", + "key_seed": "D6FA314EEA8A2BD61C0026516EE4BBE03620F11013CD17BF19BDECED48DAD396", + "ldt_key": "6E37C54D3A143CBE7B690F3659BEF8CAA0625960D88AF699DB29DF90C5736DA73B66D21C27862AEF984590069B4AE542156C381B864A53EC0ABAC796027568EC", + "plaintext": "2645CE96C6195ABECA54CBB8FE9F5EDE303E3C5CDF49" }, { - "key_seed": "4BC857AB21F85D7019DF55B6DC04F222274369A6825692AC9D63BAC25EBEF47B", - "ldt_key": "339C8EBBED3C88C1DF8C225F355E7FCA833874458F3CEB85BFBCFADD4F8C7AA04F860152E98A9E89142EFBE04A361397802464894E4F2F5B927A9750C8FC78CE", - "hmac_key": "978FDC344AEC925814FC8E3F1663024915C9F2A95710F44A26BD4B2D4A7521F3", - "adv_salt": "5669", - "plaintext": "037BE6930684D4C235D234CA7DA8B515", - "ciphertext": "BBB7E9148422FFBF79C506B00EA1F86F", - "metadata_key_hmac": "E82B43F4CACF8E3D7047B484EAED8BD8FD772ECA7C7BA18FAFD4B6C991FB0723" + "adv_salt": "858E", + "ciphertext": "43DFAFB88F737CD8C82C984CB63BC53B98", + "hmac_key": "CD7244FA9000586CA5C83A99ED4DD525A73847DA15403371C6A78467A30862E2", + "identity_token_hmac": "DD77C9770E7388701DEC7C9DC97B7225F19F06784F61E4E263B746EAAE9667BE", + "key_seed": "21AA1006D01D948D7F3878D0CF6BDA2C9FBC0CEA090147BE500062A8D1929620", + "ldt_key": "C39D2E1F194BA9BF4055F389AD3AF0F55366F803477CEE608DE018F0166793400EEF3F04DF9CD38AB01F39095E7F6CDE09BCF245EF38B91B29CEC130EA6277BD", + "plaintext": "E6978A5DF9C6EA4F57C8C0FBFC5310B6B6" }, { - "key_seed": "B0312EBB99279933724BCAA461A59F19AA0550107076D40297E3D91A64D38864", - "ldt_key": "356D1D2EDF489DAEB0263916DAE62352FBD32BBE14DF306846784670B02EBE9B51368877E277A914CEFAC15CF3C763AF5EF0FC5E72CA2E83D994BD8F6FD93E14", - "hmac_key": "48FE4A7DE06D21ABBBA9CA919C7F339C0D6495D38F8137FFC57FE85ECFA396C9", - "adv_salt": "FEE3", - "plaintext": "007455C803830AA1122787EEF4FCD71F57C29C06", - "ciphertext": "E5739DD2B3172E84F5FCF17EC6C92B3BBD3F86F9", - "metadata_key_hmac": "575F6793DC05B2184C21426FF985064CB2E6EEDFDB051C3E7A61E737E93BDFBC" + "adv_salt": "9D72", + "ciphertext": "3D546469EAF0B3CD40680CD1882A0BCA2525061690554DD3B0EE22A2", + "hmac_key": "93FE3B606C24EF0977399A2143DEA58BCC2804ADB51BCCE9033C3BD3B49BEF56", + "identity_token_hmac": "EB660374A3AC93ABB905EF49D6E0DF3AB2BDE95662A71D415B18D6D337DE76D0", + "key_seed": "DAF10E64CA62A68825D4FDD1610D1EA3F73DE73565F5F6A5EEF34F079FAFFF31", + "ldt_key": "1828E0C0EC85EAD87246E8ACB196C2D4E27F00B9B05D96942C95E3F90E423FD120BDCCA4C851BAA87D6F70B1F09C90E7C01C56499B8F7EA3EB066C8993317056", + "plaintext": "DC107CD0B5CA7D542327B0BFC785C41AD1F0E2EB6A4110361D276674" }, { - "key_seed": "A6C270332D6B8DA4419490908DC76D6AF162E819BCB44C69BCB6B093C86025DB", - "ldt_key": "C30EC3DD334F09F0618822C3E1D93D2C59EDE05F15712A173D7CDC9738132A441FBA14AE65D6D772332B1CC80C3DC880C232A39258A21A07D3D613D0DB1958EA", - "hmac_key": "07F6BD1301DC800AE625475240241CEF294E0ADFE29CE4645295DE28644C7468", - "adv_salt": "E79A", - "plaintext": "69AED23A21571027A99FDBA8937B3728C7C8FE22", - "ciphertext": "655793F9E26F92328504E2B1746C35D060D57F47", - "metadata_key_hmac": "72F10799AAB2A3D1CFD021582F92EEF45245914E540073B0BC950D12DED27C5D" + "adv_salt": "0B4F", + "ciphertext": "745859D632D7B1A0BFD118D13B85B1BD", + "hmac_key": "6CA7661C2D4B90D3FB24F85C546A2DB1BBF013C3549B522CF6043DEBE145C771", + "identity_token_hmac": "0DEB10E261D6DEE81268BA4AD15E41D1FC6C4F04E73F12742400D3D2B5359C5D", + "key_seed": "D049B2FCD0CDD4596F93D9D7B868E88B3EEBAEF43E61A9FAF9158A6150A1EF5F", + "ldt_key": "B78A86927FD21E35A74BBF2CB83826D0F3C3ECC36930EC8C995597CD2EC6F1330B8D82E2F042C28B2493AB37783596F98AB85BAFCF4764201EDD9922B1E773F4", + "plaintext": "6FCE05ACE2E2B53392362B97920C3E12" }, { - "key_seed": "1B3DB09F98B49E09FC7A7712DA6975A435C9228A8A10A4B7100015B1BF2A9170", - "ldt_key": "D7E460C842C14011B55A3E5D1DFAD8EC4D1751A06687A6F3038FE52F9F900C9D01CD3907531209C5699E7611A1C690854D1A83B4B4CD468EBA6C5C7A1BD9E433", - "hmac_key": "D62A374514FF4D010C6C706F71DD837CBB77204E8238133CE41DCF6C3DEEAD30", - "adv_salt": "2EC3", - "plaintext": "91C3CC39C1DFA0A98DDB8669F8BF4100C85EB809CE6E96A23A8F76D1ACA2", - "ciphertext": "3575C1D1B970E2BAA292F39FFB0886B7FDA0C8F7A6ABFE2E4C23186F9796", - "metadata_key_hmac": "442509E2FFDD39BDB85EA97040BD519CBACE8B49971B68D7E06F058A87EEDB89" + "adv_salt": "DB70", + "ciphertext": "9F6ABD20EBD91A3E4927662D302423DAFE74ABC3", + "hmac_key": "330915EAB5F5E75DC6747A893474BACAFC7F116FA2E693DEC2C7DCD6155A2FEF", + "identity_token_hmac": "D674C7AC837A05191E705C9ABF59C9456F8BE9B1A6B67910D5469ABE61403905", + "key_seed": "0961CBDD12A7B644E7B9E702271E4BA6017F429A6DCA110FF326CAC98B37AD5D", + "ldt_key": "7CFD66C5CA07AC6A4D530CA801DCA0338448322A3BC5A2B56BC028C0F31E5BFA5D8098DF92F6062214CC8A4E421F873B1388F26F4A7F8D97123FA9530A8F9B32", + "plaintext": "479F535BD5B82ABB82E5F014CF3865BE9453DF17" }, { - "key_seed": "98C8FFD6BF66DDE36B52F95264970F3ABFA03546BB9E42EEAC73B861C4668EC8", - "ldt_key": "7D0C4847D29D4110156447E82106A97715A6DD664BDF3B4262FBDCAC71C6D9ECC87D7824B1E65E741DDEFCF9BDD149C9B127C7AFA9E1FD73CEE66C441CE257EA", - "hmac_key": "17971EB7FCD0281E0C5CE05969BDB40EBF768CB8B73E816DAE761DEFDE5C569B", - "adv_salt": "D5D8", - "plaintext": "2BC85FB9B4B8597E0B7E02AB5BB183F4C0", - "ciphertext": "C50688FC3AD46A9C15A5C9818864856D7A", - "metadata_key_hmac": "44DEE13232B3537982D17A0B6EAD9BC8357C00A7C590D7AB37B6F9C7BDD259F3" + "adv_salt": "F62F", + "ciphertext": "2E39B8DE8CEA7523627609C0A76C1CCD3E2122F82ACB2E7852", + "hmac_key": "04322B90B4ED3D3621EBEC8E27E4683A67BA2C82041403D26035E310A32F9278", + "identity_token_hmac": "AAB5BAD093219054629BB37AA41D83E34E4445CD4057D056858DBF8EB4397034", + "key_seed": "9B3A74F8DB6BCA0BD09AFFFE06DD78211AE9DF8F11A9F3A3417B39C2D01E4AE6", + "ldt_key": "1CAF350FD51CBE30E00A92B2198A17906F0AF4D45236595A5C54903C666744DC4DCF78FF098677898659E5987B35E6C573C3DE83750C29EC69853C3E4C353177", + "plaintext": "9D51CE24875ABC6F43E164ECE4679180826009C2D183A261AC" }, { - "key_seed": "1906EAF9DA10460DBC7CAF2DA723C0BD4A087462C162BA91FC9BC9C4B0D91264", - "ldt_key": "06E58CF7DB917DAD1A8FC436B25FA4860AF9B0D8E80362499F2F80D294AA0BD88F070E0DCB8A9D801B35EE4FB587955B751658B9717596272CDCD7BE1DEB7D33", - "hmac_key": "891198DB242A226E7D1BE5B08E5F786D38AE8C8FBA009EBBD8ED26DDBCD7053D", - "adv_salt": "A352", - "plaintext": "DB729216056241B8A2BF9A9A362DF2DB5F", - "ciphertext": "B75F7873302FC7FFA4AD4FB9A320C96F43", - "metadata_key_hmac": "B26F69630F29582F0516D5CFC12BEA2380CFCAE49FA987A491633AA9E60CA89E" + "adv_salt": "1DF7", + "ciphertext": "A5B4B307838B1B761B52ACDD98AF4D8867DDEB43BC3A569D", + "hmac_key": "6EAD3FD46FF8E8FD4ADFA97D709120A07496FD0D84142C956EC9ACA2E35D7F0B", + "identity_token_hmac": "C5945044702D6DCE67A45EA35FA28C217C80A952C8A5F080F945F9B5E98C6394", + "key_seed": "CD657B540A64750A595AA0F644B5876CB07BC81137CD11CA44484CE5183F1993", + "ldt_key": "779E316C081F91AAD914EBB6562A7DAFC2A9B4193D92B4888BB72925FBC5D31DC279AC22E56575AF1F77DC55513EA0A0A02F248258A0799A1C7E9FBFF4A8F9E3", + "plaintext": "067C8183FB8641294C5BD71D2CC9384B27448DAA7ABDCA51" }, { - "key_seed": "C903E4AD3E9CF458BFCCE2E1F5AD924523C20A7F1C73FB6A02F04C49D95A6066", - "ldt_key": "8319E13B431FAE7314B09BD90C628C05F469877FE0F245D84A6C3670AD60C65568B6A2CE61DA831A47C53AF8BDFABE1A6461899CA0ED14CDEA3946FD0DAF302C", - "hmac_key": "DF550EE4AA78C5DA0061C698AACA07A6F2D00B041554DA56CAC1BF42520EB77E", - "adv_salt": "F5DE", - "plaintext": "6757E541F331AE07400C295A4712FA634A712EA86517B559862FD6731E44", - "ciphertext": "DA74D9D92E47043556FD82FA4D22E46D18A8A9A2313E2BEC9FB9E8D78267", - "metadata_key_hmac": "0AD05442F7AC6ECF628844E9C3C7046FB926709CBC6519EE5775DE03A42CD811" + "adv_salt": "C04A", + "ciphertext": "FAE99D33CA11035E83B25BD44716745DC09E9B93", + "hmac_key": "152204070190AC7162FE20CE7F87B93854B7B3619E424A3FBA00362444CBCE09", + "identity_token_hmac": "941D8591674C49951D466350D2693FC2B3676EBB7D7B571592C4A0348084F6A4", + "key_seed": "CC962B750300AF9F8E3A0815A2CC2D9382B91C4DACE92F84E0E90B5910A205DB", + "ldt_key": "AC57494B5908F709C98B61947D619007CC5A27E8F195897BBB6A9B3BF446FB36732FDD80C6D3C7C7462AED8D6E8C2E0D3B24A0F3C8A3D4317FC26E56FC446E6F", + "plaintext": "CC2CB221F08C8264834D8828F2C38F8CD138742E" }, { - "key_seed": "BEADE49E784716A7BEC51E332BD5540A25C1CE71A278A54CC07B649D048A5561", - "ldt_key": "BD54BC42F56935AA1FC5D2A8C76294DAD6E40F00FC306BF33F29C0866B1B5F5F1261F78B08B6D61736DA480626DB27E07C9FBAD41582C25B6EE92EB2394163AB", - "hmac_key": "FB9031E5428C831BD0969F4EDE7CBCA5244142D9EFDDA4A03FEA452D25A0254F", - "adv_salt": "AABC", - "plaintext": "63EB8971511A43049DFD7EEBB8075D82521F3654C458C3B5149DB1", - "ciphertext": "C3A855294A2AEB154347758C6FB052BEAFC2789E60573AE8CA80B0", - "metadata_key_hmac": "E5FA9F69D44C7E68DDC4F687C6BCAC9EA78690233AA3C545CCED835E7CCB2021" + "adv_salt": "DDC9", + "ciphertext": "768AAEEB82FADA42AAAC879A4A3F64DA", + "hmac_key": "E5B3B593A79805E7D13F67FD2DFE1C3F370C4DF341522BC15122C66A457EF9A8", + "identity_token_hmac": "0EFDE1DC85702380F1E80C31C0CB20CC1A84ABDA047984E0BCFB85457A913540", + "key_seed": "E5C94807F0EE9585721AB18CF7202726A9988C27B18B4BC3B8965B65425D1EC1", + "ldt_key": "860D05C7AE3D48EE932CC244F644579259E3B8A5876919A62AE0AC64BAEC10A1F3FF69031077DE256D611D210F39DF21D5354A92020C67ECA7AA107157582897", + "plaintext": "84912B83445F4F172AB424DC4B5866CA" }, { - "key_seed": "F3916DA3C3328FC1271463E1C44D533C27C59D7C5CF9C7433E986605EB958E70", - "ldt_key": "02EE10F2D441AE3C5C31E1872BB8E7C91D86279E9F8CF51915FFAF05F58A4F1C1CCBE91AF3BC8D4F61F4ED33F3D7C24B91D7DA9D8999F6576BC001307B260F75", - "hmac_key": "8D50A24DDD4DF78A0D360B9A16356C73ED7C61DC8371B8477B9C34B09FDDE9A9", - "adv_salt": "CAE1", - "plaintext": "99EFD86FEDD4AB164A959BC0416802258BA2B968E3A52D", - "ciphertext": "BA17B32F85E71560DF2F894B76661A03E51802D4674EC8", - "metadata_key_hmac": "E7F669E5B1A44A2439ED07F2743E15AE10B44C51F19E16C43FE4E2EB4346A784" + "adv_salt": "F1E9", + "ciphertext": "2EA0800CCAB683820FA2B6374C9A85F2B4F796F5C05E4E880F6A", + "hmac_key": "801BB36813FB520F44EAA47BB377F90F923E32C5FFCB86F0C05D377CB8BABBFF", + "identity_token_hmac": "FF06F63BA8B586C7CBA78803F3EDFC37961E6340D1CE30833593F7BB4993FCE5", + "key_seed": "C89DF8AE8A40E7D121F11725EDED654E9F148002061645DCC338E2A096F77309", + "ldt_key": "690F37B0BF9C0EDF8152BF5F604EF5E4B8A2158C78E8AE1A514C217D09334BF2566E50A786C8DBFB5CE89C6A831BF2BF3590EB227742D92DA64CD7E048A4ADC6", + "plaintext": "D501664DB8049B24C9361ED89794C035478F38D16F80E8A2DA98" }, { - "key_seed": "C4317D4E906F9BA4539B813384B14E530AA69BFD2DEA76107FAD0847AFA8453E", - "ldt_key": "988195FD6BCFACD2A4EDA1ADB4CE9F562D2053D41E94763B816C113A15A4A05C3F9D952831023940BC66BAF00A8C347FE77E0438990A01D42951B23B9920F01F", - "hmac_key": "6DFBAD52E858DA32E6659D7173348B34F7E015E93F1F34DB6AAAC8DA11AFA82F", - "adv_salt": "2B7C", - "plaintext": "DD70CC7F846A0FC9EBB24F46E4D61C58", - "ciphertext": "6218162C76FA90C27845628EAE8E2F5A", - "metadata_key_hmac": "0F0C6BDCED527251DD706A3D2723FDF8E70A666E190755D5AB515AFCD3CE13B2" + "adv_salt": "9E18", + "ciphertext": "46161EADA1410BA034B67EB8706239ABB492802FDF8577CE9C2750A1DFB126", + "hmac_key": "EC60B45E22554C987304C8B8BAF5840B29031D9E3DA18A8930162EA90B5B09DC", + "identity_token_hmac": "57CB29DC2EF23C376C0C0AAD8BDC33502D595BFB4185DBC714ACCF86837B306A", + "key_seed": "ADEFF11EB08514AF099F3C8D3D87C19FDD13B0FA6056BE585555BEC6A15E3AF2", + "ldt_key": "5E4D969FE686B8E1BD8DCA17542F636E8A990165943637AE48C50C65B7164DC66A0CDFEF83B14D63410D46D6F4F05BBB87C9225A5B90123A4C7BB0BCB309ED2B", + "plaintext": "F203ADF87EBE1B2ADD0A2F234F016BBE73B6E52D93D7E2DBEFF4F7A2F3854A" }, { - "key_seed": "3E702C13AEB7F8F75B8142978D771C9A6695F65E9D83724B600C7C504C06AD11", - "ldt_key": "D97054FE9C78D83EA387377C8A9DF47959780CF1A3AE864B618ADE48F6F4C74F8C5F1CCD8BB22F12B4BE04B1728C0859ED849B92D6AE9A455421AC22EC75005F", - "hmac_key": "A170DB24F77CEF208F83ABF01FA07B236D38FE276BFFADD60DFF5150AF1C5076", - "adv_salt": "E442", - "plaintext": "6566009789ADD17B430B8E31E70951A8917F2598FBDB63366EEDBBC0FA176F", - "ciphertext": "041BF4C98B853251F8FBAF522F25F3439E57A1E6F817F5D08AC0EECB10EC91", - "metadata_key_hmac": "2364F70676B650040030D6CF42B0E69D50FA56EA87C0BBA8B9127157531BA035" + "adv_salt": "D1BE", + "ciphertext": "F589135CBA5632A5FC722D7867B5830DC84E089085", + "hmac_key": "F618404EC6BF2914E16F892EBF50FECD660AB380AE7BCD791BE086C0DE8C1F73", + "identity_token_hmac": "B096CA6E7A55E87F1843B730E8BA39D849E8398D4D91F21BB61D349EA0B80CDF", + "key_seed": "2CA0C6DEA290320E9A19899BC25E7E04E7FEBACB862D092D703246DF905DE6AC", + "ldt_key": "5CB0D8CD3D5519B9633E59DAE23B9FCF9D118A771051D5A0DC7048D7F178011050606687E211DEA1DFF2E204FD79E4A177963CCD8304EFE8F2CDA6C59E9B5E7D", + "plaintext": "B6BFEDE720032795891C4487A1FAECDEAB3456A650" }, { - "key_seed": "CDC2C95F7099A6BCA83A96FFAA9848A06ECDE7A297EED14A9C88ACEDD485C55A", - "ldt_key": "2E02B7A12A3F1280EBBC8B9B9E73CAD6D3A708F71335C21C9E690B7C6EDB221DFF27802E34A9FECE2886BEF0328AC0B685DF28CD591BC25DF5FC6F05AE0037D4", - "hmac_key": "E037D28C89419F303C3B22704B03B9565CA4AEB4A820E2A7DAE163AF3093F315", - "adv_salt": "313D", - "plaintext": "A9334CAABC7A3EEEC389B8366574AC31FF921F4D025E74326871218B36", - "ciphertext": "71F285C42EFBC9F80DBB857BC58B4B82CF22AA3E68A6B19845CA6EE672", - "metadata_key_hmac": "8EEA0E056F28756417FAFBB00619EF84C7AF7953423F697243A35B53A98C2B3B" + "adv_salt": "3FD9", + "ciphertext": "A0379898ADC0643A4803D19A8494F80452", + "hmac_key": "4E94A209650C7C46D8305F07B0BF0678D742B091AB2CC47B241483D2E161CD32", + "identity_token_hmac": "EA7E5643E1CEC8DCAB7CFAF7ECE09AB1790A3BED6B872CB7C7BADA3E181D60BC", + "key_seed": "4CEAB4B692FB0C1BB435FBA247C7171C1D18E60D5C8FCFD364A8016741DA64AD", + "ldt_key": "B4B8D87D8B72502EFDB340C8E090883751F48D855D0D41C74175C4B4F460ADE3F5A8DFD73431C78EB58B6E20203911B37450CC8CF8D759F3838D2676C7283835", + "plaintext": "5A02766D11BCE1529A159CD54BBED5EFF1" }, { - "key_seed": "9E3A32C3CA43D7DA82838C21DC8D7A92B34E3029F2150EB6AE08E21E54DA60B5", - "ldt_key": "550C54BCE30C335EFC1B2CF3C69B6F36B199C11C48D8B82DE689245CB647C21FDD5697F8004D5D4409B9D7A5B5E4BCCED86624FBEB89C4E24D69FE614BB6F4F0", - "hmac_key": "84DCADE652FFB2082BE54A83C761B8D3BCB3D004847DBC22B7B4F56E1DAD1AA8", - "adv_salt": "22A7", - "plaintext": "E800C9832BDCAC3DDB8115515F54B42DF4F46A0642", - "ciphertext": "18C49172DE8492EC00FD766E94C32E65F9D94253E8", - "metadata_key_hmac": "C7F591B8ECAEE9E130E70B87D4F4CC6F0CF79781C11BFA3205DBB647ED8A6EB9" + "adv_salt": "D284", + "ciphertext": "59F8F5A7062564B2D2A76EF50896F901F64490FB4344", + "hmac_key": "8E821028E468700B4EAE999D7587758390881E984733B63F4266B09A79789981", + "identity_token_hmac": "77B6A66877A1F5F0B8D67CBF5149768D7D436215ED29C995927A0C72F7E59E00", + "key_seed": "CC127D438633974D6089E0070302248F4771920B69284BDDC10EB5EFC869AB65", + "ldt_key": "EA0932C453E066100CB5870FA19549ACC4470B59493DA3260AD7EA9992130B690FE7D178742D4D526EDC9126DB59E20905241DC065390E73FBF73FB35627FA3C", + "plaintext": "78AD3E63BF9931E2F0F0024D8E2581EC42E31D02E81C" }, { - "key_seed": "208584B114FB579D651DB0AE915AE22A74161DA1612FD66934AAB98970B4F3CF", - "ldt_key": "18F509AF830D036179EE8F5579620233859AD012DCE5CC9964BF83AD1C8BEAC752A3F856066991F3F899D7CEE08F76943D0E898C73622FB6BEFE1635A752A258", - "hmac_key": "D8A0B7CEEB921A4EAF78C315DCEF3AA1A219D8207C2EB750CF5C9A5C057F5AC0", - "adv_salt": "9B40", - "plaintext": "643A11C2ED48C3FBFB1568646836D664D2", - "ciphertext": "ED655DE4A3CCA56EF5E45CD58BC6EC981B", - "metadata_key_hmac": "BA95BFE69F798B5F499736260A9E16D1AEFDEA921BAE567166C7155553DD2A72" + "adv_salt": "CCE2", + "ciphertext": "5721107BF13FCD455C7B1709A01F9117D1866BDC71AC996BF5F4E4", + "hmac_key": "217E8FB03E291C886BA12807F04BF334FCE42A0CE97BE91EE2E804B8154F179F", + "identity_token_hmac": "7FF0C58C0820FD3E27D06407B5EA6A2295FE6E6F3ABDF2216B46B12527EEE853", + "key_seed": "3E3E9F0D4675C1486C207E8F887189244DB317A7A5CB5200038BCA439DBEB43E", + "ldt_key": "EF24EA00E39981DE418DF10A9A51D01C24764ADC50DDA5DC90839B0553AF291C3FECFA46B2E9E65E0CF10754C59D10C230C2432F96572CDCBE8D061BBCD33F23", + "plaintext": "193A16F2383DE9F25BB8A9CB1113F5E52CA38DB8F6C3CD45025D05" }, { - "key_seed": "AA182BA6F55C8B6E248AC754E735F24C73089ED81455F7327B4FD32CB10986F8", - "ldt_key": "C6AF6AB4ECA397CA4C72F2231C91A31EF7BAE7402F214BEE91A26000A41C83AB49DE9F83A6DB14C1B7089B98CBD5EF56C821152A777A62A69224CD24C87214E3", - "hmac_key": "B3B94FD6E36ED7EB23C5FFB2B9FE39AA8E958C7968B54CC1374C3DE2CACCF83C", - "adv_salt": "BDB3", - "plaintext": "6F1112EC7F239D89826A71A35CFBA83A", - "ciphertext": "1D2EB0A2102A78B09B6FE01461420937", - "metadata_key_hmac": "901621B523F0C0C37593BD1C9A8992A11D6E00B308956B0A1CA1B20342AAF924" + "adv_salt": "1BCB", + "ciphertext": "37C9179727A7C1E836A404C48A747DBD75B58A1D23EFCE204D5F50", + "hmac_key": "8F2F4BE5B3169271086E83C71E9B9348ACD2912565174BBDB1262A7840F3E32A", + "identity_token_hmac": "2C386D3797A9EF6E15F6D90A7A5182C45ED100A6E8920AF8823B25C022FD6C0F", + "key_seed": "C81AF9A3D6CB7150C1E8008737E5ED33F6F088BDCA4F6A6AE7E6B563CA23725D", + "ldt_key": "CF078C229178D3DD9BF48F51DE27B2D1432250CB1B0F67F5D2ADBECB2BA5743B017705ADA1B6CDE56CDEEE13A7461FB9A47955444F1992FA2E0D4886F21927D7", + "plaintext": "1D8CC80CC19E18DDB69FFD214F36869A5B78EB94B027ABCC5104B2" }, { - "key_seed": "6396EF1AB8B1AB63FB63917F29FED78EFF57ADD13B849349B6537878F1580A9D", - "ldt_key": "2D5ED0EF006E0D023A2D76051D936964DF8DCF63CA1E0B90A9AC4024E3544DEC4C1EA88718DE3B1B60845BC8915EDE331909415B024BC421BD5A4734ED06CD71", - "hmac_key": "BCCB2F43EEABA659F0962C885B69037243F54692244700EF83FC4CEB4CF47AFE", - "adv_salt": "4B17", - "plaintext": "CF7231679510559FB935294595824823", - "ciphertext": "6CFB394FA9522089E320871C70D84A65", - "metadata_key_hmac": "B1DD5AF143DB53CE62FE9488C54E581B16C31EA6FC2B68D6F37F6497D6A8FD10" + "adv_salt": "C63C", + "ciphertext": "0F6D4AA3A9D4749A9BCF40B1505EB05776", + "hmac_key": "10582CC54F02A033EAA5FC4C1A6247EE563A74D80EC6C476E026CB4F2D17956F", + "identity_token_hmac": "B5C7278B84491072B0A1BB498A2E0D16F9236693B481A71DB14D7E79C2B3ED65", + "key_seed": "3ECF1FC2E62DB5EDE18A4AE95C634824A9E6E81E750AB74696D102546E9BBBF6", + "ldt_key": "B33996937E2E37A41407C8ECFF867D3CE49057412D968E513BEE72602616D70D04B9A10760CA5B104D2887FD24E92C925160529C985D2DE000B9A437EB2C6322", + "plaintext": "D11094AD21CF9E7D6B40737BFE75D3FB57" }, { - "key_seed": "CE60CB333D364A1D6915B37FBF1C92091829DE2B1B6B7B8FC4D1349038A44D6B", - "ldt_key": "63307367255949F902F770F3F3AA6AA0DB1034A93C9B6D177182C097AE3834F55BB44259D53296B3AA80A2A3A950DA6C705A39248AA4A53EA2EE5029A612C339", - "hmac_key": "B140C0E4E7FF5F891F795DC224BE23C376A6C2CA6E7828DB2A608B37F719C050", - "adv_salt": "49C5", - "plaintext": "16E6B82B12476FF394AD541550943BCD0687EA15B290F238", - "ciphertext": "2BFDC35E78862910FBB626C9A124242A0E3101B4D1B506A0", - "metadata_key_hmac": "6894A92C027E0D13A0A17F0A036D49621D8C092BF64B37A6D5D7F88719C34B1C" + "adv_salt": "93B5", + "ciphertext": "34B5B9320E5AB45ED9D317B281D5C506DC3377BD4F5E6579B71A4F", + "hmac_key": "B78802ADE1C1E235840299682F4A887AABE8C0C7CE302E97C09E43D3A4E63C42", + "identity_token_hmac": "FE0762AFB535721F478633F45AA82B45C8548F57EC506D3E7FC99B3987310ABE", + "key_seed": "4E4307B12B7D4AE374B141DA13BC0244F405590441087FBC4E4CB601BC8782C2", + "ldt_key": "9385F28378E997B357479AB99B537A917F4D7C8C035093E217498284F69BB904ABC851B91EE639134BED28EAA649C42234101B86380F195457AF14F758CCA0EA", + "plaintext": "C762C9CCA95E9058C382EAC3F85AEFCAF9577C2DB3B179B203499E" }, { - "key_seed": "E9CD02A26F9C4AA593C8FA3161F71A36A5B01B5997CD37E03FBAFE255F0A9904", - "ldt_key": "82A0D8C3F7436C38DC56950A6BAB1295ED7AE5B20FD624B500E7FA2CD76949B47C6E7E92194A97D02D034F3FD963F3AD58F798D73B3CBE4E7FE133C033C7D2AA", - "hmac_key": "269411A0CA960F8EFFD49327974D759EC1C658FCDDA6EE313917010EEA06CCE1", - "adv_salt": "B23B", - "plaintext": "EA133D6192C98F803D46FA4D09EE84EDBB432A315378A6ED5BF6691B", - "ciphertext": "D85B0CA6B5E9A77FD2700CB0AC3D0C193A465F0E7CC52729ACC1A61A", - "metadata_key_hmac": "58C3CAF1EEEBF55F0D7D27BEF516986EF9253BE453A8487EA39F56CCB6D53DD9" + "adv_salt": "6D7D", + "ciphertext": "A811F10BA24142D7655D84A4CCDFEECF3B0773EF9D68156BC4BD4D77A30B", + "hmac_key": "11651BC94CBD0EB53B3B6A1797BECFBDE748A53174416F85E68C5501E4D7EE40", + "identity_token_hmac": "8E35E56A14AE67F069C07ACF655233CCE20EF2E475A9ED06EADA6FD2283BD2FE", + "key_seed": "48DA18F6C4A2E8FE8FD65595EE6EE30150F88DF47E6E5533D15235B529A02B40", + "ldt_key": "7D030CF23298B907E6C330364F7B758C7A875B400FE712F01AF511483AFB07DB068BFE744E17914360041F451AD9416B046D784A79BC4427C1CBBD7416F8F6CC", + "plaintext": "464436B39F78BE4FC6F322354DCBC1899F26292243F624814D9F3DE898F1" }, { - "key_seed": "D3BC36A108E864BF1013B0DEBD7C9F340442341A5C70EF7A9E8C437D33433EDA", - "ldt_key": "99DD0595D3FCECAF7D98E0C26266CD1B04CA62DD2558B5021061A7F7E1D419A804547B513DACC7529952FF238B9B4720D62D4744B023925A88E5D3E24C3B26BB", - "hmac_key": "B3681FA6E9112A91DB33D045EE54F3C7B914FE9FFE835C03A38D1D039FB56AA1", - "adv_salt": "DBF4", - "plaintext": "3557B3C4BCEC8E7B0ACD0A0134C47494A460F799E821C675F3AD12", - "ciphertext": "449CCB6BB67FE23807FAE60469DB06C7D8E72C9364FF1310A27D37", - "metadata_key_hmac": "4BB084A1FA068300E490F67B29CDC91AE45DA0C70709BAEBD33BA231AA2B4CE0" + "adv_salt": "8E8D", + "ciphertext": "04EEE502D4F5AA60B94E0EBCDA1290264CEF1649BF30DF53A8", + "hmac_key": "318D9B3647011FCB71D9CF4BC713637895E073207CFFF196A3E6D770C9B6219B", + "identity_token_hmac": "B173B54D70C518BBB2A4C5A2A7334F2982577822AB1E2D487C365822BCD2A83A", + "key_seed": "A921F57C7C59EE2F89BF1F0EE7EEC865590A36BAB2DD2EFE3B3AC65A4354145A", + "ldt_key": "7B3BA48E4648C073143D02617CAD45493A55B77573662AEFFDAF23420180BBDFE152E8F954A9D43D85D3B3F1D0F35908AEF63832F1B1AFFEE991E4E4940761B1", + "plaintext": "D8E9CD99AA75B35F474AC5BE6D6ED95795D12C5AE8518D62F1" }, { - "key_seed": "6DD1A5FDC69B668839D44722823CB1CBEE2827A78943761C2DC92349283BD34B", - "ldt_key": "1D3B333FB54E240DFCAA8892332A7E7323F93A4ADA114E9664BD7564969182EFFA6C193C0ECD2A67B18113E4CE254AE6C8350ED57126FC9A4D909860BA509DEB", - "hmac_key": "D73A2C7983617D6F346895DA10012E42A8DD8FDDA9D6B21F3B8A91546E638848", - "adv_salt": "A1F7", - "plaintext": "B4F3EBA80957B3EFFFED35FA1487CC8FDCB0", - "ciphertext": "4FA99A5587D446031AE0DD322E28DEA1CD3D", - "metadata_key_hmac": "FDD24B63C520BB33D124E74DDAC334175C00BA0CF350F0CC6D3CFD51A57A5B12" + "adv_salt": "C3E0", + "ciphertext": "24D350D1D9D2BC6AD3DDA958B3E7FD2F5821C858C5EFB70592", + "hmac_key": "E243DE29568404760BE59D1836D791ED8A0C78C7CAF4ECD49EE9AFF65BBE5076", + "identity_token_hmac": "E050BDFF46A32F0299A083563206F04F41ED6D9E4A8489F18A73E4209B41ECDD", + "key_seed": "9EBCBF72866BA9B742577C57F73FFFDC3CDEF13FB54257B36D95CCA1684FB626", + "ldt_key": "2CD45198DC0E1036046E67B0EE1F3899BDC2309ABF334F77564C7590066FF1D6833D9ADEF5037ED5ED0B6B595720159A81E33494846B2CC23E2E5F1BAFC7D87D", + "plaintext": "3E082216CB59F558991B00747C27BCAE6139C37BE41AD6A8E9" }, { - "key_seed": "1521D786973327F460210B6E4A98241DFD125976BB346CC05582B705CF2C81E3", - "ldt_key": "4273A7E59F40DB5DE89D3EAD6732B12FC8A7671B4CFB6DF7BDA02167B0F3414CA1EAF32BB53E1D892B9932DE2163ECA9CF4C822179C89BE705EDAB667C25B58D", - "hmac_key": "90F0E29BD73A103AC87C3F60753DAA6641DEAA3E9034C25BD878ACD3EF14B7B9", - "adv_salt": "650A", - "plaintext": "98FD73B1CBF4A46CF1B855EC6D4DBB755716B2E1D2EC3C", - "ciphertext": "56A77F96DDCB43A70530B88669BADD12F7F16E4DAC74D8", - "metadata_key_hmac": "1E2DDAD56AFA04DD197D0E75BC60A3A303AE2FED2250D62BFD5613505DD3CB2C" + "adv_salt": "CEEF", + "ciphertext": "59B25F6C47627DA4090B53063D5575442F06A08DE58EAB64D68BF8FAECA7", + "hmac_key": "C4DE203603F16FB3FEDD229456CB7A60E417D00A169DF9285A508B548BACA491", + "identity_token_hmac": "A23559801DF147E623EC67E779ECB673E84892D6EEB2678438BCF34A0457F675", + "key_seed": "2591BF35AD9148C46AE34848FD205F6EC1BBDF2B75BCD9F6E2604EE945CB8D23", + "ldt_key": "154130784C121CE60A793A0EFA716E469D58A70B5D8656054DEC2D55A145FFE990D454DBBC0FA2BEAAB2F340F2C7F7BA2877F8E742FDA6AA2E8F3D8FA5A4FFC9", + "plaintext": "7F9C2C7BC22D8B9E0C60B2368F36BA901CAE0DF7BAE687C5E0F92AE9865C" }, { - "key_seed": "76C21E2D70694F810B5F730962CC6EC1E5B4F9542990E15DDBD2ABEA92B4AE69", - "ldt_key": "CA8485DC112182FEBFFD7DF96365F8E7C97BAA0701F516C191DE98E772FBCAA94E87C062A2A69D94E66942D262D4C5DFCA62F2B293BB485B5AD399A1192FB5B2", - "hmac_key": "F18E562B465B4D05D17C30AF43DC2A2C674DE6BC09D50A31A11E4246AFFF22F3", - "adv_salt": "26D8", - "plaintext": "8CFBAB03370DBAF4228B2BA60A4009A8", - "ciphertext": "B5F69C72D7F281D68236E70FEFF3AE85", - "metadata_key_hmac": "0F9AA07E623C81AA9F497CC6DDA13E0C6752170393EB205DFEDD3EFFBDA5E959" + "adv_salt": "7E2B", + "ciphertext": "1688E19A95742C16497585EB5E1BF8E729", + "hmac_key": "E7EF33D0CC8CEFD9926308D187A6613F8A9F1CE207CAFEC51F327407D5398438", + "identity_token_hmac": "59C9BBFDE59DB9CB354A905DB22215E25B747EC69CE22F9B76CA8F27C2297E8D", + "key_seed": "92343E22B489FA1C9ABC0BA72ECDC7D9A0398C02D4FD57734BE451C0A2F124E0", + "ldt_key": "0DE6ED726ACE044F30F18455137E7FB059C9EB0C573376FB0A3191D1699C747414EDE680A061AB213C3877EA9CABE725D6FEDB3DC7B56BAAA386471467E7CD6B", + "plaintext": "CCC3A15107F749514AA4EE7F2DC19AD77C" }, { - "key_seed": "9560513480DDAD0E1413E38F9D6E897ACE1A7632D596D23769498B8BE29715B1", - "ldt_key": "10F5156C4B8B7829C1C4D6F145DEF13B9A324C35D5A3E4820F892584844CD853D94FA8CE5A1AD2823F59D5A96A4E9EC4411BFD13781392ADAAFE6EE12C85ADBB", - "hmac_key": "25FF587E6307020556B1F164B8DE84074F17E3035DF540FA6F9DDA4D2C890ED3", - "adv_salt": "6656", - "plaintext": "2E131D72176A4200B363D13D80DD10A12A698AC0A1E099A4523F13F6A9094D", - "ciphertext": "8E6C2B66D73724060636779E93F2EB02534AD93613BDD424AD387554C3257D", - "metadata_key_hmac": "A3B660C747BDDBFB92E8B48B6DFBF3B6A927EBCD836B98968E4DBE1A225C0CCF" + "adv_salt": "1FC5", + "ciphertext": "CD7E0E0FF578E0E80BDB0FEED0C5491A12C346A27380D642BBC13CC6", + "hmac_key": "1288291EC7FBE104F8EC09DC9A78E1A47A8B362AC9A5377FE85B3D9EC50F68EC", + "identity_token_hmac": "6BB5AEA5ED0C1F4B56470F9D6629BBD29A23B6A601765CC004639A6A5E8BA626", + "key_seed": "14E59B92D58461D1093A92B936326986D141F71DAE9DBEC2B3BC4508345D2976", + "ldt_key": "6B76182617C20677B7A2F132F6F2FE3FA0166D7BD46D2DCC75645F95014EE9E1E0A553BE54D654E40A95FD2C56503487E7E163A2F58E996EC585CEEDCC3C47D0", + "plaintext": "9B1143A836ED3758A3D16D7B11621BBBE28A42ECF87F325550DE8192" }, { - "key_seed": "8A7FA1444A5AB5FD9C754FB5C17B24521A4BBCA87304668ED171E63ADE00B53A", - "ldt_key": "62E5CE70A1E00AB0344AFFC21660B81B9AF7DBC98E2B3BBFB0580F95CDF6607EE86E3E027910C133A445A54EEF164717F60BBF581FD911D16C16797F093AA376", - "hmac_key": "A8796FDDAFDA42BEA46CFAFC15B3054AA95C7C6D9842C056C5D5CA3290870A2A", - "adv_salt": "3ABB", - "plaintext": "96C67D0472764E1FBA67D78C9E23130EA569D80850D67860705DB18A84D9", - "ciphertext": "E253ABEFA95A3005FF8A637C64C4979D527823DA079C56ABD7F8A226254E", - "metadata_key_hmac": "29630F405187DF2E46FD1568B885C8F342B6A0C736D05EF2708A15E89EB4F77E" + "adv_salt": "2D53", + "ciphertext": "EF83ABA138A689555458B97DB59EA003BB", + "hmac_key": "16248A307CDC2A250B424BF36988B0B6366EB803ACCE340AE88B07903183B401", + "identity_token_hmac": "64C0A74AE467B4603FD291FE6B32B49D8DC36457668015700EB89BC987095BC3", + "key_seed": "335FB592EFB2916D06EEB949514C40E4407490506AC269ECC30F66F70DEFA836", + "ldt_key": "A282B486080966A74C664BF30CE063B511A8F4FCA7DFC39D81C5BD314141705FBCC539418CA0CD6B5C5781D52CBFD4C1A722D1D00CA06F55EB85C16B7F631CAF", + "plaintext": "DEB6E4513B1B0CF9BA4A98D379A8E13403" }, { - "key_seed": "C9CEF79735A49737B2054FD28AFD49A32BC27413A645B81EA41ED0976EB2C1BA", - "ldt_key": "CCD43C05EBB5729D56B9ABCD430ADD48AA324F888273F11990F29B1764976AC52F579204BBA9153C1C87E895FCB10EC57E5C27F67166794A4D056114ECE090FD", - "hmac_key": "84E721FF3054B223F07971A69C4EF2065FFA8BEBBCA6E21F86D3195404D10CBD", - "adv_salt": "DBF9", - "plaintext": "3EB9E1F6C5C925B9DB9B9358054A7110AF19FFA771", - "ciphertext": "05A4431BF908CAEC6B3FB847C2F45CE4CA666F2669", - "metadata_key_hmac": "256FF13A29DD13554EA3B53476950960BA8FF3404DA2EA647D657DF077504116" + "adv_salt": "8ECE", + "ciphertext": "443127411C98DF4DA8A06D675255D709508C854ED3AC3C6CA0847DD054", + "hmac_key": "6E8C7E7E1CBE3CB0917F0DD7041B80C1ECAE2DB5A1EFDAC720830B4765F8F719", + "identity_token_hmac": "61644E0BFF22A073B2B04529CA04C34535B85E1D426FBBFF574FE28628D9EA31", + "key_seed": "40FC5113E1557A72F698E3AC3EF051FC3AEC386233954D61C936FD3B66882422", + "ldt_key": "775686C9C7FC526CED20B718E8675697776199E2371A558DE33E3E78C53CB734A2E933C02C41F8826DEEED9769EE7E558A780CDACE276D40BF067BF1000AFE80", + "plaintext": "6CDF43EAAAB305E79BBE1AD6FD7BD70A630E9CE50591D86A22456FB556" }, { - "key_seed": "E48BFCC68FCA39CFE1CA4EDFC684E37D20BD27D56257CB0EF4F109AAD61D32A8", - "ldt_key": "DB6EFAD0649A4D700171A22AE74D0C87CD78A15BC2103B2CDD10676190D519227039177E4FDA4003C6C2770E577BDAEDC1124EC003996B1F63B0DDF882988BA4", - "hmac_key": "868E89F711B4890B4F3309E16C33CF8DDF9BFF32E94B3B9CBE091BFA3D9413DB", - "adv_salt": "DD6C", - "plaintext": "966A5DA11194D05AF55AE62928946B3066E956B3C268878B8B", - "ciphertext": "A4E406ED299EAB31C8EAA4179CC35F6F5ACD3BAA2037C68340", - "metadata_key_hmac": "9A521E13E251F0015C3740EA21D84E108263125989719A2E7E3C847DC4DC08DC" + "adv_salt": "9D91", + "ciphertext": "170FE1A9E44F0467B74F1A40C3B7DB88B0AC12490B5E1E", + "hmac_key": "F32663EB2FCE17B3C25297D9984AFCDD13316E7674E140818009F46F029C9513", + "identity_token_hmac": "6868CAE353ACE437F0217688CFFC414E64030D7C867D1D1E7A047D2B356A02A5", + "key_seed": "74958FA7D2A63FCB32DD38BD6CC4247DA571817FDC2D259DDF4044B7818E9B3E", + "ldt_key": "615CD06A1E653207B0132535C85839525E479E67E3438D8A3A8B8739F41D5FAE773429F1B70899136C3614F9E53E3ED0266B03A2F8C2E060B76B3AD8384E9B83", + "plaintext": "013B4F0CDCD662C220CF77C3EAED783048FFBA61D5E1B0" }, { - "key_seed": "36EB0F6236D1072C71FEBE86953757768518126B710BF644C724B22C6E811361", - "ldt_key": "34D51D3D4D442AB9EDF9CA19D84D0A23BA2DEBA4F49F1322BC37A5CD72BF0EC5B7183DA85F90AE029F8DD752E177CCAE26D73DB63F27F99AB39B4C2027FA5731", - "hmac_key": "6CF977E944CD2F42EA05A0F833E39E855FA219D30EA6ED07A85300654B8AF653", - "adv_salt": "D695", - "plaintext": "11C0603EFF5B63E3700C4441ADDD8BDB8B8D5413B06D0B547B65", - "ciphertext": "1BD66DF65CA78541E3EA94ECC88C352450710DA6F22C5283EB15", - "metadata_key_hmac": "7D26D8BECD71E3C98BB5B60493D5FBC5594473DC1A333BA123C4007B10FAE74C" + "adv_salt": "73A6", + "ciphertext": "53911B8E6FA54286BA4DBEE7E103F4B73D10C873AF7EF3267F", + "hmac_key": "9245A0A189CFF97F3716521EC06C7B5EC28ACF1D175CF584577FC31677033C55", + "identity_token_hmac": "DF63054ABB719ADA13BF2FE69F0224962CAF30A444138646A14CC1B6274C038C", + "key_seed": "2CF63DF744353224F434313B0468607C5CCABA9C26C8258F0AF5D3FB4A3C4693", + "ldt_key": "2F762E3AEB80C1106D7774B3D0C211B302972CD0A4BF7D9C988D537436F2400C264702F0A630D1E69EF470A5B7094566F82D876412FA64139F0ABBF0CF9D1596", + "plaintext": "0D309F7E410220E23520E6BF1A33CD6C1AD4ED1CEF645339FD" }, { - "key_seed": "9608BC776DBA4873F0BFC953265CB8E4C36966BFD6230C35B63E723722458E08", - "ldt_key": "22E962B7ABFCE353EEDA7F16CDAE977B7F496C938A663465C36BBD2B433A03F7A477190B8974A5ECF41C29ADB0E767A8BDDF4636F369C56E83EACF1B39FF3CE4", - "hmac_key": "E69E2A790681904BFD66D09CD60F291E84DCACD490208F5682DF994291F4B3F4", - "adv_salt": "4F53", - "plaintext": "E125883CB677E805178785ED8FDC525E0054E48192CDE9", - "ciphertext": "7DD36CB0146BDDD1FE95606A15CAD69164EDA3CE7C7B29", - "metadata_key_hmac": "0EEAE07CBAE833B659F0236D45B965F7ED423CD8CAFD921E8B52932AF0FC36C5" + "adv_salt": "E85E", + "ciphertext": "BC1027E1A064D40A93DDFD479B7660AEE059519A8A173319D356B8E6436EBE", + "hmac_key": "78AE4E730FD438D605FD3EC3404C4C80BE1D406A0E61CB50987D90CCE12473D3", + "identity_token_hmac": "0D6DB7E94AF7A07B4EA5ECEDE6CCA60D49BF612C3B109EA0AAF5E7CF888813B5", + "key_seed": "121F2970696FC34F1BF2518216A6440D18EB8E3BC8618350E112CA0B30859022", + "ldt_key": "888E59808FC618FD9A4F7E625953B25AE6372B526F65870AA04C0677BEB554EB32317057612DF6B344861C3006989237870C5778FBE834DB73E3B30AB8A0BFF5", + "plaintext": "0D41C7319A3282F415077C042913C0A790D7116E74A94B267BF37F2F7617F2" }, { - "key_seed": "B2B6B53D51B08DF36375C4F761E4EF7696B8727CCC69C055F59E1DFAE7465B61", - "ldt_key": "FF16F56B0EF97ED2DE15F7210D39F17D7E2A0809AB33B6F03A48B0D67FE60258A576E642A001C160068D183C6B8D691C42E7B9B5833AE1D4EB6C174A40022167", - "hmac_key": "BACEE2A7FDB9343A443199D0AE356C3FA81F3B4E9A23AF015111FF65AA577396", - "adv_salt": "6F8F", - "plaintext": "D802DB2CEC8B2D5C60AD56EEDE2E9F703208D9074C87F301CDDE9ADE", - "ciphertext": "940E65E0B35E2C55C95DB6615BDB983157F4E487030E089FD7BB36EC", - "metadata_key_hmac": "7BFCA5F80A1C0151FCB6AF5B0254A5FA6D1C1D3838171C9BA7239D2691BB7DAC" + "adv_salt": "F380", + "ciphertext": "C01C4C4CC32F8211804EC1F30D8D4675CD39366E908A6DDF7C44FEBE", + "hmac_key": "ED79226508FC7349E3672C89302BACDF6523BB1EC1D91D978FFDF7218FBDBA6A", + "identity_token_hmac": "F1EC22047C3EC3185DA15CC5FA206103DC0E97F90D31D5F4D85DF66B20739402", + "key_seed": "A090D3D433D62BE1AB26AEB4613C96F44079A2BACE83E5E98028D7A3BC6F463A", + "ldt_key": "F882A283703F9B5F4A6F5CB7713B2E65220AF2A37711145546AFFBFB3054C31F520838544B4E5411DBDAE1BFE2C8452E73B954DA1EB1EA931EB0752155732AC7", + "plaintext": "A0D92E271704EBD8CE417F16ED748C52A32CF2F0D6BAC91710E3D32B" }, { - "key_seed": "12DA1EBEAA3D43E08E600C6AA716B207D36C6758802374C0E4EA7C32BE675D34", - "ldt_key": "062A158A5B903F3101F185D3BD4D40AAACEB2790C556E5DDC9AB463A5DDCE0787CF1179F73956D6C6899607BE6F76FA9336D6FA0B4CF1A2282675175910CBC49", - "hmac_key": "3E8D020F7D8B0CE5D79C8F16F0343F04D7336C8D27041AFA158BBD005EEBBF6B", - "adv_salt": "2D65", - "plaintext": "402574521678897BBE04FC669DC869542E54E549331D42DA1A", - "ciphertext": "12F37BB97EA1AC0409881C93DE6CCC872B56D1213F19E6F7D3", - "metadata_key_hmac": "E0FB235D6DF5EE15F51D8BED378CD53C176A20FB9C609AD165229E0A7619EC29" + "adv_salt": "00D1", + "ciphertext": "52025755D177839E5AFD6875F692FBB4F228BE5BC3583249390050E95EEF3C", + "hmac_key": "148D8C9025A23C28642569A13F70B90C8B4619F1D37B35610A73D7DD2002AF51", + "identity_token_hmac": "9E1144CC5EC70D0B8243E106516B277E53B5B75D2F82B7CF573F79202FACE05B", + "key_seed": "B00E867E23E7B5A4CE44967F173961C584D481506AB467A3A47589280D06F719", + "ldt_key": "BE576CD183CD359A2AAB6A3FB1D000BD1002FA7EF62BA2C68EFE5DC97A37C2B646EC64B21B5D17AC9AF991C8F4846DEF855D6D8ADDF344D112FC0308E1088F22", + "plaintext": "852403CEC6446A618E60EC5E46A4CDFC960B8D8332C75A403F680584E7F19C" }, { - "key_seed": "F7BA3402556935A790BECBF1BEB3152EE9416A022F90FC3D4446DF8D97600191", - "ldt_key": "919BBF75697F5344409D34BD5D708B2A60272FC3E0B75378331B62BD1B4E1A11E0091FA4900E9DDC91E73AEF4D2386D9736F6270041B7B7D2843F8FD6D96A76C", - "hmac_key": "50E71BD98F83211A1F4066ADD9F4854A157849C16C07A791D1BF42B9A9E4738C", - "adv_salt": "34C7", - "plaintext": "A84BC1B49EB1276B9B66B88EFF282C5FF055BA61F169FFCD860C1C", - "ciphertext": "DA0275FCD07244BE53E80E32A4049CE8239AC7C4FAC554250CFB0D", - "metadata_key_hmac": "7D9D7E557903E103A6F55D2AB5F8CDBE2BF501EA1EAD9D1DA31F8E536E4E9B8E" + "adv_salt": "54F8", + "ciphertext": "AC2CD5D1A00D5BE2276FCD1D8B3DB3BA82E444E3C34550978EA861631EC8", + "hmac_key": "77AE3C0342EDD44559E430C72482E130DD5D71E6ECC981BDF08DB87511FA3605", + "identity_token_hmac": "A107BAB5AECB87954FAD5577CF3E081F6D7F6AAB482D1AA6DFE094746C046255", + "key_seed": "9775916C644EA12143896868986CF1E4B8B7DD4F2C95B322DFAD7B216CB23669", + "ldt_key": "888A01B8B67964BF529D506D66284D5D919403F5CE7705DB946253AC7F18716C74B0E0F15ECD96D0D60A2A6072798D0B347A7849C1137C24207C2BF9CF7966FE", + "plaintext": "62668FC2E5A380858863046818C061D30A1DDC3B29E7F1FFEDEC12DBD344" }, { - "key_seed": "B7743F2EB3B31527222B0938A519EC45B2F1EEBC58200CB62E353419232747F7", - "ldt_key": "2B9060A96D16FD2CC61D30BBC3690007AAE85FD2167855933FF3A35ED3957C8D17168B6B3219152E40CE2F0246A4038F9F06DEF59559D16B1296C3B38BE9B70C", - "hmac_key": "4623A09FE3176EC70944793D576E326FE057A72AB595FE23CFFF4845E99FC9AE", - "adv_salt": "C4CF", - "plaintext": "5D1CE03573BCA43C8766F10C03A2C810D54D8B70E2F4C5E5EEC5", - "ciphertext": "E339FDB9FE6EA518EB5FDDC3C4DCF951963F2D90FBE4090EDCFE", - "metadata_key_hmac": "92ED758AAEB7236E22ACCEBBC0B33AA23DC6727677D69594F09342984F5C863D" + "adv_salt": "AA38", + "ciphertext": "9E5962AFFA94C9143502358EA34B3E39FF5E4C9F7FBF57BB3206E2CFF635", + "hmac_key": "8E04FB092D8FA08D3E2BF791641C65E452A4B61C61ACEA5327E68F090229A015", + "identity_token_hmac": "224B6C4818E51AA638CCAC259B37F17957FA582E7992CAB661890E20C261B8B9", + "key_seed": "6CFF000FDC2F09BC79802265252E8800F974CC60421BBFF68F2089CAEBF01CD8", + "ldt_key": "3E3688B8589F59D7196CEA6EDC0193828B4E0B0D588675739A2775891BED869972F3596A72A97DF684B424A41FDE41C496D99EE49111F86A2847D5234441289C", + "plaintext": "51D1D11F873CDF7815FCE20010254FA8998ABE1525848EDD477CE2B5E2A8" }, { - "key_seed": "7E6AD26DF188EAA50EA6BB1DC755E674332952F84A902CF17351BF83B3B3D40B", - "ldt_key": "4823F16CFACE349ACECA6A797F7F6949B5CF0E86B14F2FA86A82F9E5344DD5FBA46CF1DBE420200966B1B4E16134A1735BA922829F7B9F504DDB76E87C8620B6", - "hmac_key": "C867A614967B144D921C37E855F2EC8C017A0CA5150842136B67D247E4509D1C", - "adv_salt": "DC9D", - "plaintext": "AC66F58970822EBF3EC8FB8A6BC0B88ABE4AEE", - "ciphertext": "697EE0ACABBD0F2C888A27005A568659EBACE0", - "metadata_key_hmac": "5B9CBA94B48443F07B608B1DC93F5FBA745A593296EA9F670E6F148BE667D6B4" + "adv_salt": "B1F3", + "ciphertext": "FE4366AEE6DF5F7D28BF0667085557D7CC4EA6E307A6C3295DA1AA1A56", + "hmac_key": "D3BD9864B5D175ECE39D123D43F0FBB781F637891A048FE8F6D6F2D44BF2DCC3", + "identity_token_hmac": "25CA8316EBD6A264FA762F72AFFB221FFA7F65F8330C12A3787233907D956D18", + "key_seed": "5814F434D390EA83722FA8F0D7BD91F65090BF6DFCFD42C28E4DCAEE4F095B98", + "ldt_key": "04AAD7F99CB9CA6A1A8246EFB82C3183BBE4B225D7C95D52403C82F4A819805D41ED1DAF64927ED74F63AA3A4DA3E2BF6B4D0F04E64CA51CEE24415AA512399A", + "plaintext": "8F3A30C6EFDE14B9367EDFD4166756D08226C64A78F7495CF001392510" }, { - "key_seed": "3AA30B6E523E212F9BC549B1468624C3C39D4446C1613F99EC525E90B563E114", - "ldt_key": "32EEA16100A29DEEDAF425D5EDCECBA51621B8F1A3FFA232D0804FED7B9F05B15A3D0638AB519640E927F61C2107E4A56556B054CB0323CAFF375A144FDDA9D9", - "hmac_key": "07A1CF987BEF7C4DD83B831FFC6A67405ADC35B465063AD3201A15570EE65B6D", - "adv_salt": "C521", - "plaintext": "43FD7D528C2B9B610C8AEEBD9B136D6DABEF53F920BE", - "ciphertext": "DEF7A393BE5094EFA7BFAC518C014979B32FABB4DB26", - "metadata_key_hmac": "9AD8D7883FF0D6C9F2408EA1D04F6036C587CB9275F9EB53CACAA220F6B8AF42" + "adv_salt": "5DBB", + "ciphertext": "D24534D81CF934D117CF8A227B974C4A8670CC0794D7786F77D4", + "hmac_key": "AF4DA47793A376C768CEB102145C644670AE13566778327953E8B7965B26DC43", + "identity_token_hmac": "E359B6A3EEF1E0C5A5EC1E7B6D3362FD31F12AC9C43E717198CEB14F092A0ADB", + "key_seed": "484F18C39DF6592153C8A653BD398D961108A717A0AB2CC282813C6FD258C0B8", + "ldt_key": "FA78F41F44E5AF7861C11D23E563B91FC32370A0E3D40BFDF07495E9519EDEFFCAAC939D1F5C3B554265553307666CE02FBC31D31F29FDD3632BB24F39545F54", + "plaintext": "5F0D1829F7DE91792483F92AA7ED87012A64FC38D41F4D4461F5" }, { - "key_seed": "E9E8F9E8DAC560A5CD0136D59C94099D601EFDB849F599A3B58078BDD2DC3E96", - "ldt_key": "A437E4C55CCDD67EAF8DFAF9C65213E8A2232FE624662D4B682ABB8A5B9B9D21307BCDE683C42FC22F0595AE41D59BA016140A309B8825143E5BF5C12B3B7549", - "hmac_key": "6C4768193DDBB1477C893AC14A87563FF249654574814C4153DC1DE46CD9A2B6", - "adv_salt": "3813", - "plaintext": "856CFE7BF88E2E8695F34DE8694F3DFA61F2B8D93A148264E4354B", - "ciphertext": "86EDC0F3E4F9A9BED9ABB4DB56C2E2316C61097F2944F2306A785A", - "metadata_key_hmac": "ACC695BCF1063CB8ED7B2E456DE86FA0CC74C1FE44C4F637AF3495A409F6D0C9" + "adv_salt": "33A3", + "ciphertext": "F492673ECCC90ED523086900A06AB897FD03C0CB8BF74CFBF5FD07", + "hmac_key": "78E1D683B105EB15A33B7AD6C2DC0695C7848FE72A0BB1993988034823F63C7E", + "identity_token_hmac": "3F1FA207DEACA96FDB08E1619653117B42922CBAA1088CAF8225B248875774E2", + "key_seed": "632642AF207B26D998D5605BFD4FC57804270E76AFC0813B101AE5E25A8F06D5", + "ldt_key": "6C447AB95DDB5972EAFBC4E697BBA41D9B8F3393F4FCFD8AD83FCFAE4F719BEF694C1588300C2653C665B62BB6523CB333809643530A758A7731771A9E39D751", + "plaintext": "4FB623482FDF7DFADDA9F32F0ABB75DEDC8F516639934A414C23B1" }, { - "key_seed": "53E237DE3511AD7221FDC3EAB249724CB9FBA19C4FD08E65915188264C639AB7", - "ldt_key": "16A2905D758DD04EFD7715AB796FE5E5CE922B3458733A8C369C4B5C1433A1597A50D58832593831F52B33FFF07EA67EBA625635F9949889CC57B92D99E39868", - "hmac_key": "E29C815883E98D5DA9C4CA403AEB9EBED8F7590A15500692563113D74CC57112", - "adv_salt": "4005", - "plaintext": "77358652AB18EE47794341B2438A77770A358CD1E9A00DC0BBF79E0D5E", - "ciphertext": "3606F86BF8017D9DCBC8442C1D9C50F4B853C6DC6F1E8121F59113B4E5", - "metadata_key_hmac": "DF01BCC3F032DDE4CB7FA01CC8EEEC96C5339F2DA060240CAB3F1C8F0DA58E5F" + "adv_salt": "4D1D", + "ciphertext": "DEF23BF8CE6D352C03F684873197F1E126EF", + "hmac_key": "25669AAEBADA492252B93E6D7E94D75312D3B78B28D3A42B5A170F1532F91498", + "identity_token_hmac": "C4B1D109778B6E1C0069B0268E640D44F190AFE69E6E1C38940F05B24B5A705E", + "key_seed": "35344CFB928DD670C8F9B554CAFA56B71E898EEE153B7960D62444999D4F8EC7", + "ldt_key": "4DB7CD0D9F6E7E9B0985432CF28B73C6C04993B55816F6631F5E6B1EE8E0E25B653BEFB1C72F19B409972D02076DBE50138616ABCF243B55503BAFD17B1354CB", + "plaintext": "56F164E945994FD2F9FF17FB9A37D2CF848D" }, { - "key_seed": "7312EB9FEA5C7CA9F945DF91E6CC5512844A1F3694FF1F8334C14A8CC1C514DB", - "ldt_key": "9B14E89C2BFF72EEB7C9F484BF20DDADB3716055A55DA9CB9629F98B456E8F5FC16D03D399D8D2077668D58046029E1BFA35A75B22C0E2C66CD79F17214D3F40", - "hmac_key": "CBAB6250E2F312A36E475FB89B17661810DA0F6B3E0E54980CCB409F72B6FB11", - "adv_salt": "8A4B", - "plaintext": "8649F437928B3DEB3271CF32D20C82D92B0DEFF30FC189B17E", - "ciphertext": "3742B52ED6A5033C1E3B9C4AC90E025761AF6F021A36775D8F", - "metadata_key_hmac": "3725CA84C82101D045522383C65A2CF82DC7ABEE776A2598CE6DF5979738CE9C" + "adv_salt": "171A", + "ciphertext": "62E2114BC26661BA79826CF62A546D1510020961EFFB600FB183DA4464", + "hmac_key": "01288B1D7E7F8EB6FEAC69FD20BB11AB56D345BCF0AE49A674170946A708FFE4", + "identity_token_hmac": "69F504A58777284025B9E33C2CE8585958A1E21763624D3026D4C6EEBB6F2157", + "key_seed": "6C0304E547553359B89861721D451170273DB250EC89F0386750F8AB208C4F7A", + "ldt_key": "8960E2FC42E9F317C808DF38E0B971944F5F1E971A77999120FFB125E6F78A046018AD83467760FE0FA2D770259D54663845BDDFF24E846969BC0ACEC57C8552", + "plaintext": "3B0C65B9D02FF4DD90DB2099A0A0CF10DC35A2E7C1DE8A281D15A1AAD6" }, { - "key_seed": "1773861943D0B75137AC484431C0E3A5A01AD365E210D49FCB600ACA63EED3FC", - "ldt_key": "0ADBB1905A684E8B43901DC20C5D5320A3F446E22F6897FD4000893FEDB66A21B2BFE78CE6E9614642444A885392BFECE5D01D9610971697BBB0243689AE20BD", - "hmac_key": "8DE824B2E5E8EE81E6853B2B6B5476F01D8C32956110BABA92A826E3110D9E73", - "adv_salt": "666B", - "plaintext": "8F451FB1E8EA039FD315E22C77752A81E0A5", - "ciphertext": "5FD110690047A765DBB47E7F2AF9AC7A2095", - "metadata_key_hmac": "7094CD4AE6B7C81475FAECD9C12542CA1B0BA018DB216BA6437512E09B5B7F6B" + "adv_salt": "D96E", + "ciphertext": "289873B493AE26B051E1BA5C9630C03B", + "hmac_key": "7F34069F1E02C5863E59B49AE7A09A740FD9EF2130FE241930853C6638F6EA5C", + "identity_token_hmac": "4EE58E92ACD3792F79BAED54D9DCB9AEC99C8155666FA18BF47104C5205E4FBD", + "key_seed": "68E0BA10E0C3A18E5D61EE0370F54593E0288CDDF65C6C8057300CAD29B090B7", + "ldt_key": "441C58203B54555CF21A8AC286512FE9FD850074DE73056687B0C84F54891F2F51BB71595DCEC31BB425C760D62114706423EB5522B6938D1C26CD078C9E4958", + "plaintext": "F023B0469092095BF11BE2C8A3D1F538" }, { - "key_seed": "C81619628FCCA36C3333A9DF317A30A38E992B99B4C613D54EF5D8A84E041CB2", - "ldt_key": "DF08364FCF56F754A435A293DB8F061F63EFEA9B7E6677D85F3C7FB184C6CCF577A2BD0ACDA5DC1D2523EE1F17124C2165FE283314C5570A77DF48ECDC355AF6", - "hmac_key": "139F438F13C38116CEAF0008113831A0B2B4AB26C2C2C67E7E0789D457A6FB58", - "adv_salt": "B2D5", - "plaintext": "8EBB4881DD7A89B035180226619EA16AA87857F56336D921", - "ciphertext": "4D405B876C12A543559F879C464E87A318B0E3778F2C884C", - "metadata_key_hmac": "A51503260CDB7DA3B8A8A625C7D0FE672E9C4DFF1A61083507785911782EAB70" + "adv_salt": "387F", + "ciphertext": "121B881D86C73C55C54B58ADF7C74888AD718266BDA183", + "hmac_key": "F52485E359F8C8AE2A9A2367E83F4DF59B3F9671371995CADA1FB7D676ED9ED1", + "identity_token_hmac": "38622556DA5CDA145459709B8A2EA758E36C4E7259ED1CC23EA3F16BAC9B3942", + "key_seed": "AB297422AE12CB88D6B1626645362D6A648B602421B1F50E9C5726F3524E5443", + "ldt_key": "B41F670F935CB3779A0D6A10E1CBFDD2262402DDA4EB4AE875F49D685BA4F78B3558D08F2A918E93758F1452ACAE11B091C11B0E43541BC631E2B640F6145B7C", + "plaintext": "F11D62D12CBB4AE6584A56A3C1DE1ECD6618AF34C198F8" }, { - "key_seed": "C40DDC0D09883D89AB43D4868A619200BCA6AD3077298150EE3B24A538259899", - "ldt_key": "9EAA4B0A788B9722526A0CDC24D12CAC087BCEBA93DEC1BF91A75B083E237CCC81EA08EA411E17E3D456BD84DD62D3767B816D71495013A76CE01381BF079DC1", - "hmac_key": "1C06DD06F878794583907EB532AA977111887BBC3C04D206E6AAD6C4B396EEBC", - "adv_salt": "6A17", - "plaintext": "7F48ACA677EA0623CB99F4489684B63644F4", - "ciphertext": "4643C1A64BE170CD2FAB442F1744774FD2F0", - "metadata_key_hmac": "50B67E416D25520E17E3AA41D9D91B40E161B46EB4A844194F830412B51DD82A" + "adv_salt": "1577", + "ciphertext": "BDC6A5298AAAB19D43FDDEA801F547CF2BD10F55FAD4E7A9627D43E9D2CE", + "hmac_key": "6422A087D0436BE49D14DBB2669135E591FD7ED3546E94B1656B72FE993EC6D0", + "identity_token_hmac": "79FB70FA422A1E985FEAA92800389DC7011B114BFD2CFBAE02AFCF0869EBCDAA", + "key_seed": "A9AD292C8B18B7C15EF3FF48C0B96C7DDD41035ECC8CA2FA6E693DD26B9FF0B9", + "ldt_key": "4EDC9FCFCA44CBE5FA9F4FD05076E268C2B6B995FDEA5614CDD788830276E8A44AA2FC4CD016500324CCDA2A360721C6228938461164A38E7F2B5D3BD93C3640", + "plaintext": "6ADEB26B7E31EBFF8AA3033E03F4D51F2DF26AB6DCE786F4F36B92466070" }, { - "key_seed": "5303BA3383DADF741D20FA46C3EBE1B0857E0525C88E7D60491C7CC09BC83133", - "ldt_key": "E7BD40E7A7AACD7C889767679F2A6F8F1ECD3EE7BE80C954E28CF4B18060ED8112FFECDCAF162A21F8D1A310F941B3B144B6430B2B02F284E3C278C246517BD9", - "hmac_key": "2B9A31A18F3516FB7A03E7A0C018507499CF16075D6CDFE395F38F466133D106", - "adv_salt": "F11C", - "plaintext": "62C335B8AEBC64111E88458AC17DBCAAD9FFACE7F2F34A62AAEE1F03F409", - "ciphertext": "7A187B905C3A923F2882D66C11CA32ADCE01EC46EF2F606DCD92E6EA1777", - "metadata_key_hmac": "98B6F0CAB8B8DE46C4762284899C2E0AB18BF7FAB1016A312DF886AF3188056A" + "adv_salt": "651E", + "ciphertext": "C6E7BF11F4C60727F4ED2FBFBF6D0F2FD862", + "hmac_key": "21FF3858D29A9CF38E86C40AAF83B5BD0A60B317906B4E3F4FFC2EAA718890EB", + "identity_token_hmac": "AE6CC49ACDA2014A5134AF8D3E318243EF342317E7B341D00AEC6839F31742D4", + "key_seed": "B4A98978D3F552C9A81DB5BEAFF274F596ACAF4E4A6612E81A064DEE39CE4F16", + "ldt_key": "A82FD91507080BC8F2FC5B4C3C2088752FACA99047CDC4A1776ECD1E461E28012398058C220DFA667507060C5D71ECD840F9DFC44E5DAFDBB499571EAC48DA9D", + "plaintext": "0E1AE48BF75A15436F226724B006968A2B6C" }, { - "key_seed": "753528F822537C4D415D303A60E262A1B2940080851F56EEB3A139ECFC542FBC", - "ldt_key": "D0DBC4CBA4FCCDCEA4488E96818529AF39194E4CC727D4E7462E08E6489FBC514FA2E49FABF7EF2D79D4C64AD5BE6411F22A95BF0D6395FDF6D1A6D9E571D4F2", - "hmac_key": "880716AF02E75D557E6F5FBE217E25EDAEAC5D4409B167D29C8F5D84B163D3FD", - "adv_salt": "126E", - "plaintext": "EDDB6DDE5172724C4AED0FC8DAAAB28D89C4278B1A40E3332944BC", - "ciphertext": "1C6207B72F07609CD5A780F30D8FCE434C4F9B27AC7168709B5D5F", - "metadata_key_hmac": "2AE916B61DA3329C97B25E50CC2E3F16BFE28E811CB4EB84D317B9FEA37F1448" - }, - { - "key_seed": "E758DEEBC05D7496829489D628C73ACC9610CEA8156F7FDCEE71F5CDDFF19FF1", - "ldt_key": "798A19F3F00AB6043F151CF56B6E420F92579A1C7BA59EF6BED390547F269AE271CC0AFDFB7CFBCFA9D7556E7E4B65BA89C7DC769E7FCFF84274175A592A7124", - "hmac_key": "F3773E92263D77390B619936774B47E41B4EBF50ACE1446B76738E5E538C83A2", - "adv_salt": "DC11", - "plaintext": "31E392CC99247408D4560CAEDC95CF866AEDAE", - "ciphertext": "3B4814FF273551D37E33D7A957F066730E3B7B", - "metadata_key_hmac": "FB168B3C5C1D90160D5A4E9BA3E77B485FBEE19A96B0201F72694C7DFA6E1E5E" - }, - { - "key_seed": "2B47278A6B48C731880FB87A2DCA8554639BA9D823B4747624B6E2859705848A", - "ldt_key": "BB04B6BB8AB23527697B9D9EBF422C242C98BE7E3A61C52F4AA88980F3E31BD92FD51C039F907CC7D98AD0D2ECAFB1D1CB872B07273DB62BD1DFCE1D148EBBCC", - "hmac_key": "45732D754EC4492F07C42B598CC4972345C04FD2A0B9AB260F24889181095855", - "adv_salt": "5FDD", - "plaintext": "51EF41FD9A1E6E3239B05D7B663E7628DACBC8EC579831740ACBA4BC", - "ciphertext": "677BA674167B0C7C62245041C90F894F93BCA3822DF31B097DB940FE", - "metadata_key_hmac": "665F0B4DDF0ECA663AEAB45D5C0F221EA736BFBF23C240D11FE78036D52D919A" - }, - { - "key_seed": "885E516FA5AE3EE60BECBB3CCD69F3277FC70FB98E93EEC511764DDB6DE834D7", - "ldt_key": "C7764DBF1114AB161E4466C48DB5A441746E5634D68FC267C974CDAA38F867A7427F5844EEEE7EAB25E8CB811DEFD7A40AA1C38484D3949E3507FAC5067DCB31", - "hmac_key": "6A46572FE998C253F213534B0FE6F875C944DBA34174045C1C991E050EC07E0A", - "adv_salt": "2985", - "plaintext": "12501D4AAC3B854F1A56A0CE3B2216F5327D8296777C5763B0299780", - "ciphertext": "F18310F993F3BCFDCACFD8E3A61D97114FE73B2515B952DCC4505860", - "metadata_key_hmac": "9A52C36B094238C0C3FBC0774B8CE7E5A4624EC70EDE250F1580548EB30BCAC2" - }, - { - "key_seed": "D56B601EE412A42981E5F9BF1AB7113ED37F06B99BAD84128C1B29FCD99AB55A", - "ldt_key": "6DE9F0640326E8EF67D01DC252C3888F5C4BA0E3B1C8504022E328A6E679CCD1EF5508681D1A17FB7E76EB96C41EDDFFFAE08EA207A99256BCBA1C008A4BFEF2", - "hmac_key": "B734884B932BAA0ACFE10228C97194F9CE395B3EDEA2A0433AEB92B21C136E1C", - "adv_salt": "1810", - "plaintext": "F9F1E08CA0D03CF62B915AE0FB3F306D288F3F3F9F78", - "ciphertext": "04EC3FE723D1946741103511D1E7ECC723BB88E33060", - "metadata_key_hmac": "A8383FA1B78EA4D04A5AE8E97BA985518DD9AC3FF6E897C71C3131C63BE1AB1E" - }, - { - "key_seed": "45BB14939A3827965AE97E6C098D34E1299F61FC22663695D0548DEDE836D06F", - "ldt_key": "C2B7B55F49F3EBD92E0488A8F131E7E221F122EF963CF74EA0CC84ECA58AF09893D5BFDE1A2A5FEEA4560D0022786FDB112FC2070351420938DF112A850F2225", - "hmac_key": "D754E3E689B9D6345A6476D6BCCAECA2E9E0D3BDFD71D6EE2FB3375F3891DAE2", - "adv_salt": "8444", - "plaintext": "04763A7656C5DFAB6A837336917B595F28", - "ciphertext": "84564DF47E50AF227B6F8D5E63A1203F0D", - "metadata_key_hmac": "49DDEB980A70C46077645F40DF71ABE5B2AAC895BA8636A5E8505DC9B9C1F47D" - }, - { - "key_seed": "5EA520B5A5F71495CFACACC3768168C9BD00E1923095EBB6C73081E1332A34D9", - "ldt_key": "C59E13A7E1E3C3660737B37B29786658536BC0D4A04AC75F1092E7EC9F7D1CA21DFBA04A66A1AEF372F509DFA6A23E1574E14C701EBEF74BEDF3AFD989EEB01F", - "hmac_key": "A3390A01124DE94322178DB2128C964DCDB914898F356FB7D92F7D65AB78F226", - "adv_salt": "6967", - "plaintext": "F4F059C16741C8AEA673ABCE63B6B6FC357BBBF1A362", - "ciphertext": "846E2631110F587BD6F2E019B8385A490F5B01E1389F", - "metadata_key_hmac": "501FDF96FE16C164ED5CC86C68CD077855490CFBF23D6E33E1207F98F2B6C6FF" - }, - { - "key_seed": "6D086EA32423D3814829003D2A4B80A3CECD9806E554E770769CC2DF85F17B25", - "ldt_key": "D1ADCC0ABD0A7676AB6F624B91EADC14FF103711E95F61FF3EEBEDCCDF6F771472EF0B6DF8C1A4148D740EF7CD7C74D39E114DD6C8223F628A4AB1D7EBB1DC52", - "hmac_key": "14F5EAB189EDD46596F0C6476051F0FAAFA98C0FFBE8AEB97EAED13FCCE61721", - "adv_salt": "1B39", - "plaintext": "2B2414E9FC526303C7AFEEFB88BCAF9BC6352EBF1D47CF", - "ciphertext": "95D27ACEECC6CD1683CA568B16FB1B352D2A49E4ED261B", - "metadata_key_hmac": "9B37A7FDECF53FC87FE673C5DA643F7CC3750BAF69AF8A459E46377E3299554F" - }, - { - "key_seed": "FBB48C887B96BBEDFB63CE3169BEB2C9F83C3EF8D691F4DB40C665581E609F66", - "ldt_key": "65F098FF1543E2057A402DE0DF3464EADA379EA9C1E332C97AB38E803DC90EE811FF5F143D180D13C1216421025E8A966B6BB5A427D0E38595CB894104F9656A", - "hmac_key": "43BFCB395E05EC1B3E0F17D91DD4142BB379FB902D623CC20F226FD79F7EAD04", - "adv_salt": "1B93", - "plaintext": "EE6A2392F7F711B335293E904630456BF5D8FFA11E70885B062F4DD7", - "ciphertext": "4C0338F081FABCE8971695F79D1A50D34258B7113952EBCA7CC56D2D", - "metadata_key_hmac": "7F8D64FF7F7CE6F8992179C7D46821B384102D113FA632713077D2EC2567AD46" - }, - { - "key_seed": "4C3068791225D0D0CE172BCDA1C834CB3F6D5A3EB3A8715F091241506F9D4FFA", - "ldt_key": "3137D6D9EEE8A4534C7EEAE2AAB3546C0CF9CD596393C9F6868D05ACE1CFA0AD6903A5EC10536DFC9CDC875C777601647452E5F77CA0C4B61371F4D5346C408D", - "hmac_key": "2FE9676B4AA49986EA5DA2401C133269B786317D646252D76304C6F054BDEC2D", - "adv_salt": "A13E", - "plaintext": "B1327C0315DA8E72BBAABB0FE86A8742", - "ciphertext": "7E6507EA1FFD3BC7DB35FC4592BF1AC0", - "metadata_key_hmac": "9540042EFCA7FC661E337DE0077115880ABD2CC39A8B5BEE17C2A5E622EDC1AB" - }, - { - "key_seed": "4DC6D9D1C0BD2CCFB35512AAE3C47A6EA53F01D531E19243E8E34DA7239E6910", - "ldt_key": "085F9E2103793B6A062D69718245D6123E14DDFD370EA9140BC977D4B3AADC7A17E0DA21D9D32DC4D0415ACB0EC38787F9A92E96827576366BCB453C47FD3B79", - "hmac_key": "C2B5F83A37BB2B09C48A4B09A030ED89DCC7352A81296D8D25CF3CF3D3DF1915", - "adv_salt": "9365", - "plaintext": "7498C00FB8330954C9AF29A70172F609D87ABBC6B4C07AF2542A3F", - "ciphertext": "51BB7A9BD05CB79A9F53C16AD3ADFBF4FC7ABC6520CC165F5CBCE2", - "metadata_key_hmac": "2170D9F7E820117052B1892384C5EA49850C672D0B325B02D2B920CEF51D50C5" - }, - { - "key_seed": "2E93A996FD7BA54B6E223913A6424A9E78C2BF654660D7A101EB60106F6E2D34", - "ldt_key": "086D83C6B9EF677F2FF0751EBEABCCBDFD3CC5AFA4B19F100BA9C5BA1906858AC5B0ECA0CC49BEB013199F658366EBB40D58F42A0CABE9C90A9B6A41D2D4A8F1", - "hmac_key": "81E7CEDFB01B32C2F1B57082D75A594A791267558ABCE8A3652C3BED7D1FE201", - "adv_salt": "9B0C", - "plaintext": "0CFBD922038FBE12059BB9C89566EDE98C94662754D0B5", - "ciphertext": "95757F09585E76F32BB65EAD5ED22A83C1654EC08290D9", - "metadata_key_hmac": "323A8A88C47EA852B343839D8234230A847E954D4BAD825DE2E22B2039A1F566" - }, - { - "key_seed": "A741ADDAC9A6DFDFC504013B902D3DF2940160E903B7D22C1EFC2B2386504A97", - "ldt_key": "37F1AAB33A89C8BB79C8009D6A29B565704FF38641CC79C0CA09D1CDA73CAD58EC9628289C083846D764724E64763741CDBD0A5F8E75C24E28D883BEF3B0D221", - "hmac_key": "A9358E0F639E9879D985DF06D547CFF8ADDEE0D1F1BB762942C1359706D94676", - "adv_salt": "FE8B", - "plaintext": "B855E6C34E803990374A952351683A3EE11A9DC9AF8B9B95BE4B77D161431C", - "ciphertext": "DD5416F0008C369D9A9EEF4391886B8AB46C7DCD105FD186AE3100E591538B", - "metadata_key_hmac": "0BB1A55A428C404E16494855A9171439B2DDE2BFB708884DE308F8AEE3DF9BAF" - }, - { - "key_seed": "FC20FDBE17A2011B670A9A5F8191190AF117822ADD3C9030969753C3AA7DD0AB", - "ldt_key": "8A2725155600A03DAFDE9BDDBDF51D0350A6DE3BAA1210A54E09AE6D9657B7C975AEF4E2CB057DB80C24B5FBD3601501B80EDD38E4E0B6A4F941719BE8E4B21C", - "hmac_key": "687CD66D7CEB8D59724E68FF1EB7602C34F19FECDD9BB41966C944CC7A1B0769", - "adv_salt": "63E5", - "plaintext": "1FFF9123DCFDA90C84EE36692CC1454675E8621AE5DA6A65", - "ciphertext": "CA92DB91D551BEFC693C508A10B256435AFCEB49F0FE3096", - "metadata_key_hmac": "F544A2B9F0207AF8A88E47FE408E926331D448C94504F6100D59A1AE6CA95BB6" - }, - { - "key_seed": "686BAE3B084557346B32DF983153F4F1C3233B975244D358FAE4C9651B66DFAF", - "ldt_key": "DE80CC5B3AF1318B189DBD54E27B0DD9477E0D6A034B057E69DD1CF029DB2C0750AE67B47333C142034CEE7B2A68885690B109C5E0114CD165D2C4BF57200056", - "hmac_key": "BC7AA3D96F3E8688DE2CF939F0AB6B9E5797F0717CAEB0343A35E2D0ABE577F4", - "adv_salt": "A0C6", - "plaintext": "1DB632F5463172CFE9BEFCB1D8053FA2CE49989688", - "ciphertext": "3D54D60D010B56FDC56DC5AC1221BEE7C98FA6AA66", - "metadata_key_hmac": "9B6D110128D2868EEE1E539F9867070BAD300157F0F9F7BE79E4A3377CEBF699" - }, - { - "key_seed": "F48CB050D56C56F2BF68C668C8995E3E1C85842BC9DAD696A792691B39D9B37F", - "ldt_key": "2BDDAC5E9CC28E34656A72CEAD0ED9B742E0EB07ED1A62CF284667ADB0F621303A917C828AC1E48AF23B30C91508CD93D90CEC11F7765356855F9881A4CEA5CD", - "hmac_key": "1D70DD188BAA206D12D8748DF8BD59CB49E7157066A4930BE0008EA64B2BE2DC", - "adv_salt": "ED24", - "plaintext": "EB7EB22ACC5DE936DDD1EFC1191E3E03DDC084E266C5F9C9528647", - "ciphertext": "A936AD0E462B50C982065913CB0EAB81E8556871621796DDEE5984", - "metadata_key_hmac": "BAE81BAFADA8E2D62FFD7D8920F7C3444D68F993D33E1EF8E7FD1C0103BDADA5" - }, - { - "key_seed": "47FE92ACDA70B97D1C8E764BB9D85DC262D3E89FF73B6D486C3B9C28210752D9", - "ldt_key": "C0170B48E37AA9E271FCA686E30EDAA61CD32A5AE177DAD131D3510F78B89D0D090A5AF2DF4E71F0EB10BB3C12CC7990E979C24696E27B5523B8AAE77B25D431", - "hmac_key": "B4EA8E59115CC92EB24803FDF2EBF6F9E00FC35C26350DCA68A59444F57A3121", - "adv_salt": "5BEE", - "plaintext": "5DE1B7A4A4CD2A2816326C21A86FAA7709CB38BE5020C3C3C4529520B2D4AF", - "ciphertext": "B32932CA4C55F76290B1352435CDE49750DACCA224BC9A12ACDEE6273E1CAE", - "metadata_key_hmac": "6AC40E38522B09F86B9164EC5DEDC982F5D382E11BEF43C38BF2C067AF0EF414" - }, - { - "key_seed": "3391E3D0A6622A01F0F8AE2CCC8004516C08EB6481FBCC4704DFBD13BBB9DC73", - "ldt_key": "046C2F962E1CCD28BE2E42020E274382429948D78AC48C4EB89623F19F31168FA47B6B58DE6E720A0138797FBF4C57D453B63C397437ECE8666D346E43E8236A", - "hmac_key": "A1C0C56FA3D27F8C0CD451FBE60358D70B12FB5DD2CC6C66F32C174F5EC9BFFF", - "adv_salt": "C2F8", - "plaintext": "C37A278E7D53F3E73D5002CCE45E134BFEE6AB49850072", - "ciphertext": "46F94584B0D4B87311107AEB7E8B2CDC15F6E26BE24128", - "metadata_key_hmac": "48E79F8509803B096BEB4A75139582757A57080B7703BF4F95697A822C67726E" - }, - { - "key_seed": "38B9DBF9ABDA33704A2168E9BD52F90E337302E3F7E07F4B0B464ABC614E7430", - "ldt_key": "7AD9F3D9AE327ADBA9CECBC5F94DEF3AC7CF40A4449D2DCB84CABA549B0D36E7254C5C6DCEA577B897095E7B4EEC9EA8A3DFD24EB0EA09C6C51725320DAF2E89", - "hmac_key": "B5F3C37B210937B2BF1E6A4294C86FDD6FDEB026936051AD98004FF6007FD76D", - "adv_salt": "DDAF", - "plaintext": "E03C3082240189D29C59621D198725F8DE880517518F382EB96D", - "ciphertext": "10CD66A54174A7E413301E4A4E92B4D94B1CD73C76835797E1EB", - "metadata_key_hmac": "880FFE60BF390EA2D88F0B22F71D9E8BE4B1C2F856809E6CC5F310DE53FEE644" - }, - { - "key_seed": "D191625D4D507328FEB93F5C2903269007E585E68E48D7AA468BBB2C8E42B2CE", - "ldt_key": "0CAACAA6340DD428911C41F2450FC15545B2F08B3EC034F3E7E875146F2A07DD19D2C7773C26939A95757D65774142A1D3A0C634F23E4A420CF65C3ED854AC96", - "hmac_key": "F31616B1820AAB2E7B2FC8ABADBEBDED259807E17ED665F589669EA1321CBE59", - "adv_salt": "E47B", - "plaintext": "2F241ACC16ACB854D72C3D54B5D26D77ED3418E92B51502928AE77A39B", - "ciphertext": "25449D1203708D50D30923F1F8B59DD9E6FA2CE247D93770E876598985", - "metadata_key_hmac": "2D8256EBC845953D61FE235FCD7F11EFDAFCF41B293A74ED235219335B77D943" - }, - { - "key_seed": "BF5A6418C6B69957F5DB9F398C443830E9EEB83FFC7BAC667B13FF7A26906ABB", - "ldt_key": "5FD0795789FFF63B4CC94254E05BE3313D60A255BA212AE730CA97708DA619325EE83EEC295B95FEC20A20F38BD9C24C0F6BBFB8CFBD6DF2F023F9EC0C83E6C6", - "hmac_key": "D097551A0CB465F2DAD0E07144CBC511BEFC216FC7CB2158CC6EB876029CE17F", - "adv_salt": "2030", - "plaintext": "9CEE002954D084AA2BE8313064E2E885E7072D24", - "ciphertext": "887BCE7C97F197BE375984B06DC80886986DB0FE", - "metadata_key_hmac": "E132320C8132C545DF1C811A26ED663A7DC9C4308741F6326D8137A1A496C768" - }, - { - "key_seed": "C69450316ADB438F3E3770169803B49AD2F7DBECD7C80D57BBAA416B7B577C5E", - "ldt_key": "CFDBC2A26AE39B76DC6194DE00B651363EF93E28022647D193C90CBDF0EF85550BCDF0092BF4A3F1EA7DACE2852851AE2785A6F1D8C674D4039A866FE794962D", - "hmac_key": "9F3133A3629E3924A829B2AB91EDBA4DFC1624CDC4BD50F58AC6FE88293EE1B8", - "adv_salt": "AB4D", - "plaintext": "DD2639454D2EB8E10486C8EAF591A5ADDC1DC329BD493C8B451559B98CB7", - "ciphertext": "C3ED01D3C97D88E4D2EFE0AFFB70C59CDED3DDEE93588E7AB55EE5440439", - "metadata_key_hmac": "EC1C7765710667BB77C5C7841C49F71BC246F7D16F44ED95C2877871A3900807" - }, - { - "key_seed": "52493BC618AF6AA2F1A380AC1F2DDBA2ED937B11DC57B34A59B35983A058538B", - "ldt_key": "D4932E7D729E466ED4C8722AF5C7C2C54C78F7F1BEBF518226CF5B7D0F499F05DB2815252C323C6DFA4386EB9A83C3CBE18125D720EFCEDCA6079E597427D5A8", - "hmac_key": "B95A0460351EDBC7B7DEFBF4D7A593EC0DAA34223DCD8DD27403F2E9F1E31433", - "adv_salt": "60D2", - "plaintext": "52D84A60CB537611D34467DE41AC5902DD670E91B882539988", - "ciphertext": "994C6A1F16A95B0F362936579B2CD020680F4083987F302D6B", - "metadata_key_hmac": "9DF639DDF92DAE260504072CB8A1D9342EE89C50A47FB84E7960A95904EC5A67" - }, - { - "key_seed": "B8229EB01E75BA575AA1DCB4CD2BC8AC322400A7F4F07CB5264788148EB1D301", - "ldt_key": "749DB570D2483B1B6F8EB620120B14FF91A84C6074441A145C5FFB5524CBA9E4D95A776EBB9B2B6A876EBB3D6119E844763E5C2C01D3FA7E10DD820677E3FD77", - "hmac_key": "E353F7A4F7BD1A6EE7ED475C8A02584CD00173076A80BB96D40D6775421C5F9C", - "adv_salt": "FBA0", - "plaintext": "045992CC7CDBF4755C1A2477D51C3F23781ECD337548DB753AE124BA1E", - "ciphertext": "A0E1F33F23A5CA57D7DCBA88CC770C55D8EC1BBC7DF974EFA10167B798", - "metadata_key_hmac": "146376174676638B43F84DDB78052DB6AB3C0C0BBF9DC8B3594805183826D178" - }, - { - "key_seed": "4321B4688EC7D9DDA0732CD27624B1A12CCE1E17A77C99C17914B0AA82419F7F", - "ldt_key": "2699EA5FF56FEC771CB80ABD68854D56FD38FE6AB6B4CC4C43DB01A63486280D91E7980882D41B3F3F0F225319F765E62C247416866EB695FDF34C756010B8F3", - "hmac_key": "0FD6C64B002DE65BAF239D8A14E1451D49BB86C5614EC7B89B3E19D6C4BDA787", - "adv_salt": "2573", - "plaintext": "E1F4E8DBF9C3A3C5417C3D2F7F12EDC36EE7EB8A1AA7D140052880F1B43F", - "ciphertext": "9ED5913A29C5DE4870226D199E60B17B3F4093D695811095896BC5D8E0DC", - "metadata_key_hmac": "AA72421717A2E5F2FFFB4C46DD76B3B1ACF7CC874039EE4CD6CB67B5255059C2" - }, - { - "key_seed": "32A9AFB7C4797E2E058F7EF5B8865B78A9DB3BDCE5DAB7BB1C8D81276C2FB366", - "ldt_key": "76CD81D5D79AD3A9C195BF40ADDA5D8FB8914FA7FD9ADCF0803294CE111F3CD94A926F9E015DB3EFA0EE7B4A063E1B9A4070F391F5F04EA784856C79444437AA", - "hmac_key": "C00A3A044C520A6518F22D22BE38C72C6D1E5DCC4F02154EB6C8EC7A472D7879", - "adv_salt": "EBE0", - "plaintext": "A6100086D2E8E08ECFFB3CCF2872CA162D8917B98F8F3C2FACB5", - "ciphertext": "4BB5B9015F6263D206C503172D8F5764B00AE45EB1021069C36D", - "metadata_key_hmac": "162294272CB61330CFFBCA718BC1DB3E4014E35F9FFB02544E3888EDF51846FF" - }, - { - "key_seed": "AC352972B4F2719F04353418A2150136FA39C884173E78C3EF5056EDAB755EED", - "ldt_key": "60ECF6CF50A4D4AB7647454B76787F4677BD9C2593CADF4E3DE02D219DBB8301F886404225B7187B8B238E9BFE991972B9DCCB925F8573688DB39B775666D99C", - "hmac_key": "3B2820C7CDC30E8DD382CDA3821F2BF138B1052F09AC12F261ECD5210D78D72D", - "adv_salt": "1C85", - "plaintext": "4E45393C4BADC74193B091E29A1A779854008EE09B", - "ciphertext": "C560A43D859C1DC898A65011021935909E5DF8F990", - "metadata_key_hmac": "C9849ECBD12A6786A35FA3338203A2742AE4653589D39BE1DB3C06C3E46362ED" - }, - { - "key_seed": "B2C0F8149154C9CC46229E9C18369EBFF39F0F3EEF32B8F27E12F65B2903E7AA", - "ldt_key": "6F9071DFA96A1DA54B7B34A12574DBB1005DAD47DD0F7F7BD03C24632726ECA6114A1D3912D93771CFFBA6FD72654BA962E9E49C544A28F428FC854C65F05F97", - "hmac_key": "A90B7956F9F7F63A125D4602104BC6B00BE03B92165B6791D1D9C0F02A6F6B17", - "adv_salt": "1331", - "plaintext": "0E53F8702AFC1C5D707A55EF3127F17B4B37C7409EDCF491CA83", - "ciphertext": "484697262B3B548012649333839EC0871F1D80B14798F1C3009F", - "metadata_key_hmac": "3622734AE40DED11E7317E6203FEF81E2CD9EF335F1B5367EE41116F2EBFC4AA" - }, - { - "key_seed": "F4C380BEF6D3F0790DB12C2749B409EFB86C08AA9D577B942C528E45E6E066FA", - "ldt_key": "4FAC464CC036715DAAE8CC20A1EB2C752F2C4F65AC8767D807D465A285AEC934FF3453FC17496AEBCB162A5445902E2C7A7BA5D04407236BE8CCFA157E298350", - "hmac_key": "3DE1EA0A96D39ED853A9A1236CEC7362E3262BB70228264CA28EBB45626573CF", - "adv_salt": "D1CC", - "plaintext": "36B65E91A8BFFC7B97A818B27DA1746DFFFD56830EE6E727CF1080B8FD", - "ciphertext": "DA3D0EC3D7EE345446C0D3A69F59392F726388CDAA0D7FA42A974CE868", - "metadata_key_hmac": "A248A9B938D6AB6D6EEEBB4E27DA6D85FEE7745DEC464EC46D0FE23B817570A7" - }, - { - "key_seed": "B9C652DC08F8A504D7545F709EBC88B5CC9E0C2A86DD2051A7E9F03FD1CDEC70", - "ldt_key": "19B7D4078E491DF180524CE8AA2A9D8CF29F821428FB669CF8F68C4B63AE2A1B3405E1CDE97F35F10086FD1943A40DBD8528D8769D269687CD6E2D0716D8FF65", - "hmac_key": "B9300189841F2274CD6077DF4C7004AEF8968137E21935678CA34BBB7692B18C", - "adv_salt": "55A7", - "plaintext": "84EAE0A184F385D615CA217FE434FE4B4B1FF0", - "ciphertext": "F1C9E103D0E74A2EE6202667FFF755398CE4AF", - "metadata_key_hmac": "A7AF9B4A97EDEF7033EFDE386E2519656798230489248B139547FE50E5680ED6" - }, - { - "key_seed": "7E3904C173082FFA3626FA79F4AB98D78079DB04A015F395C4334872429D9E02", - "ldt_key": "CCFCDC6CC91B9480177E994C8CB668685C383A2279C4365635561EC866DF07D21FF8B6F05794331FADF21CEBF86BCF2B68F6779E9F8DF5FCF45D5B983D877D4A", - "hmac_key": "7AFE8A851490B11ECD7E94FF528BDEC30EC65B3F8BF5D27A8D4ABBE98A1A8779", - "adv_salt": "7831", - "plaintext": "B91B4DABDB93A17AF70C75FE0AA56B2C9EA29E1B450D177419AFD7D3", - "ciphertext": "222B0702B74B1B19B866726FC51FD1BAA72837E3AD36A3E09590FFAD", - "metadata_key_hmac": "CC8C4A4A380FB928319DC3B7795BC02ECE8CEA1244723E7E65DA474E71922F30" - }, - { - "key_seed": "2818D375E41F4BFF60BC5D400165FCD87311018B6F29B05890412393A0341D40", - "ldt_key": "475A78B0A6F340FAFB40B30D5E1C22CE7F0FE7FF9F193E95DB87A64E90233D707D2BD91B6A18C7FBFE1D63C00AAD1008043D61227E874220246839DECD31AD06", - "hmac_key": "05011F4F63F4DD955FF26582E8D6F40EEB1F72F6136BB741BFE66DAB3366EDDF", - "adv_salt": "4916", - "plaintext": "5B5CA3B4765B3EB9F28F9477F2BE9EB39ED6F71A", - "ciphertext": "384C0B47026B195EADF7A0EB288CAF28A8A8D7FF", - "metadata_key_hmac": "680E2C19C42A2C4BB032CC5855B21C19647F2196043BAC75060FD7BC852288A0" - }, - { - "key_seed": "293B6D7B61EC04FF8B6324CDEE0B4215696B69EF91947293856DF8AEA7A33120", - "ldt_key": "5748E0A5E16A3506C5C6037262324C47DEEECF82D89014898F42168F26AF064FADB35BEF373E83E087F47D6AD2E3ACA442A6A2A90D04AC13A9D2791EC60DAD05", - "hmac_key": "942DFA6F88C0D4A8CC126C1F4E596DB791700F51238E73B6D00329B3100B72E8", - "adv_salt": "0B70", - "plaintext": "1F2FBA9E9CD01EE3570D9CFC677639A0A200083B47CBCCD9FC6367C6A31F53", - "ciphertext": "BC7EF3E920713AEA138D84039C99CC8FB42920E1158A1FCC287B19F1EA5927", - "metadata_key_hmac": "BE4555125280C327F2AB91B5086453A69D265BF882D38F241757828021703753" - }, - { - "key_seed": "D0086215DC791940C22CA11AF2E211656608183B727E634CD45E2EFB02DB4BC3", - "ldt_key": "747DC06A5CF0E6B3544AD105C6E4646EEE1DA9C9A85A5ACF19FC4800F68D6D0E2B41D24D9F955626FECD92D44325703AEB5ADCC9EDC4FC4146F736ACA8AA1ADA", - "hmac_key": "1DF706DB07F3404922298D733E284C95A59D0F5DD078E2053D0FAF9A17AF2017", - "adv_salt": "5F49", - "plaintext": "724683E15CDFD3426D6AB9DDE6D0D125C8D5", - "ciphertext": "A7E55EB6D540B0D4572851CD336C4A66F7E2", - "metadata_key_hmac": "DAE761B6D5295D790AF8C5422DE5261E152041F5AD42A0B456D5AEE6E7D1F354" - }, - { - "key_seed": "A71F8F6908A57048100CA20664D9910F1706B692337F605E381133A6DCE2CB0E", - "ldt_key": "8386F0BA6A123E4E3B0B20F9EA2986E63BC56CA98AA781FB7847533180F9BDDFD399598724282AB64A4040E44D149075984FC3239FC91980044E5F65B35C4E00", - "hmac_key": "430EBC4CC413E3350E61482401A1D06DE152759DC4A54162998B866F768CA6D2", - "adv_salt": "C5E1", - "plaintext": "3EECB162209101704CED7A0D843B8E9B7E932B0F82C4A9FF23BD164D0FFF", - "ciphertext": "1C4E76CF6ACF99EED45D731A7D864E78709F931147BCB5005E47382B4160", - "metadata_key_hmac": "4DD68F166C06B162AD8F84C1FF167C19AB8A596D50117487AF26E338A4D847A3" - }, - { - "key_seed": "3B98434E78544A66FFCED9EE8D7B2C063B7ED7AD7AEED29B5559DC39AEA56DF1", - "ldt_key": "B953070D2CDA4353FE4E1B108004F1BF76D7CEA08019C64C888FBF702F67630B0500A7FC38231E59154786DD476C525E89F0A5BF95A1F226E20AFB5B7A856D10", - "hmac_key": "B2403EDD29D4C66C0E6333FF49EF200F68EB66E9C3C1221880849418ABD71DA7", - "adv_salt": "8507", - "plaintext": "1AE5221F2BF314C8E35555188C6D9C0E48A446B5", - "ciphertext": "7DED8D87E18E10496F0B58014B68CD2072C7890C", - "metadata_key_hmac": "E0FE0BAA12BBF15AB1B0D5AB48389D52F0846C354D34FFFDEC80E2B3059CB917" - }, - { - "key_seed": "70DE3AB2D81F7ECC3C8BC8F4842C17E71C4B4A16486C9FFF8A2A08BC2BB45F61", - "ldt_key": "D4E93D2956B9A53A5D5504A84E0B34CE48A949DEE52C821392E63442DB5973610BFD38E50FAEFDC2FB2764C298630E32B7BC2687F67F5C43773BAE4C7691D087", - "hmac_key": "07F6A1092DCE7A0ECC5A25B91770F6611A1B259E1AEF307B7CADF418D0E7BEEB", - "adv_salt": "DF66", - "plaintext": "5034C0167A1F866508665B737DB926E5B7B2FC134B10460E9C59AA", - "ciphertext": "AB4E6DD75D1D2D70BDE86441C93C6419B0FE469AFB22174D8832B2", - "metadata_key_hmac": "F6EBDDDA8E24C585D980C9848AC5B575B21ECBFFA7E42C29A0A32667C776DB51" - }, - { - "key_seed": "D6070E362975BE4208C68075DC58AEE151560F34467C339DE799AD1F4F89B43B", - "ldt_key": "F5B3013F1D2C809CD5972C4FD54DC52AE3D2CA049ACB9EFBBF415A6D70945B574550A5D69B47579426D3710F2C4C0C717EC23C7B59EF74CA3BB7FCEEFAFC8890", - "hmac_key": "FA77A236AA7006B1CF1161E8C9FD37E9501067EFDAC1F05FF7AE2C48FD5212AE", - "adv_salt": "38C9", - "plaintext": "4B7F78A6F253F71F7BC3BCA63706E5B3A87F", - "ciphertext": "D6743B0FC3C4849528CCD024E658C3001164", - "metadata_key_hmac": "A1FD7AFD923C5E086F5EC7252ADACDE857C43743CF3F6369B062191A779C7174" - }, - { - "key_seed": "06D4CD5442C5FF74E3A72B644AE3117AA39C58AD5D6B2259A95279BD4E50ED3C", - "ldt_key": "5FEF4BAFF726D4C0649FC5EFCDC7D4C7021E29AE3EE9F300599D5507BBE822237C487414AA54418DE0DDC35011E8EC387B2FB11EA242E6E9136EA550DFDBD82C", - "hmac_key": "0C520AA5513E4B47457DC6A788890108714C05BC2B949CCD3437138C6F1C593A", - "adv_salt": "4244", - "plaintext": "56CF46926F1B3C2DDAA0DF35E126F2E60250", - "ciphertext": "C5C14C2EA129C85575F9437DBD36DD9640FD", - "metadata_key_hmac": "0BFD27EB29F997A790FDC9B951BDE7FB07F18144C0332F34257300621D6125A5" - }, - { - "key_seed": "25C7513D18B3B943099EE74FA3964B6D3AF65A85BE21EC1A493463F641B0993F", - "ldt_key": "8892930D9E760904A6B57635D9191051C15D81432176129121DCE1D726FFE389FA1AE258E2782DC2536259783BE993C768F6CD19C5D42AC705973B9866F965A5", - "hmac_key": "6A22C2CEC91B54BB1DAF7025CDA3010B73085E5F0207918C10006CC02E1402A5", - "adv_salt": "269D", - "plaintext": "86E9F2435157AB4B5BE5DAAF51D5E59840D0994CE3CE0883D2611924", - "ciphertext": "52EBB65E85716A5FC5F364A92C753EFD030319E0FAAEC5F59970A5BF", - "metadata_key_hmac": "B5CFBF695F95A5692CE9E44F6153823507BA69CD40349D9F5E2EDAD8DD23F21F" - }, - { - "key_seed": "6A3819092F4B9B1D287559B3333DEEB1A5C454C60AAAC5C338C859CE8A0EDF1D", - "ldt_key": "965901C57078EFEF917F2117AFA8D10965F1AB7688428AA0EBCC2CEC5F4005B8CC9F9B5F714B07BB4544F6A6EC49DBA71EB99E23ED9861E4F051B0093A649795", - "hmac_key": "A014E29D41094A6B2AF29F5803B09958F3B413724BD1DDFF9DE3A6922F5D33DE", - "adv_salt": "FE52", - "plaintext": "3E338836AAD143675865928DE46D0569B3293938", - "ciphertext": "0CF2BBFACE17016EB783DF024A6B93022F7F8F8B", - "metadata_key_hmac": "5C921A36EF9A5BC58E6A89FF629514312D2FABF72D0CB4EC838D0FABE0B163C9" - }, - { - "key_seed": "A3908EEB18C7B14040AF677D936F841FE16B743A3B5D0C9B7B7437FC4A6BA882", - "ldt_key": "537B347160C78440DFB3BF95E7D9DE916E6B25B20A74895016AB2BCE4279597C46FE35F9308C9902A20E37CB2AD7CDD563CDCFBC31D69B7723A99F279EC4768A", - "hmac_key": "51F878A943B59A2E31B968AE9C07B76FE066AB3503583DEA9063F50A30F4B2CB", - "adv_salt": "16FF", - "plaintext": "720F44EFD5E3E49F33982B9DB21065E4D810DC5DB39A1ED0", - "ciphertext": "AB7006CA73C4740348DE94EC6B3FF8026532551D8D007EB6", - "metadata_key_hmac": "27B116068950B115B39B2A68FBA268F3BD2CD09D5863D68FEAB33BA039019644" - }, - { - "key_seed": "BEB5B05E7982F57E486E70F4D06895FC35B75138987511BD89195A92F0D8DEA1", - "ldt_key": "923863B15F3141EB2524D2302D363AE74E36E6349D9F3A0D074D098D8992465151D26913D8202E7DC45F057F02727C3DF35861D861CC31F87EE212DFFEF9CA5A", - "hmac_key": "3B6868C1DF85C268AC1F34E6AFDF5F6872754B83BEEA87E5077D50D5403D9E6D", - "adv_salt": "305D", - "plaintext": "6BAC0E6CBE03B0F7C351156BBFEE2B9D5B", - "ciphertext": "9B360B3073625C1ADA54FFFBDCA6EE7B89", - "metadata_key_hmac": "14896DA42B1F8353A2ACF69032D651A852D40F5DE20B24EE990FE9D829687E91" - }, - { - "key_seed": "6A0E2C7C7E761BB93AD9F18C39AFB835754CC36D9B6D0C37007EFCEDE3E194AF", - "ldt_key": "36F4D0B92C00D28AE0879F99AFC50B60F00CBEB9CDD6CFE59BC27E20312F4810482DA55332D168978D6BF6EE048CA21FAAFE115BC307BF91508F8FAF917F9110", - "hmac_key": "21C79D059AAB19B891D0D463CBECB7FA1C0B893C04B066E23CC1C7FFE16A5416", - "adv_salt": "88F9", - "plaintext": "108C588C57004BFB98000921739695DC68CE92D05F9252C423E929A9E2A66B", - "ciphertext": "F1EA3A73A26E0ABC68C096B43E5EC256CEB7398E705398999EA573EAC9E4A6", - "metadata_key_hmac": "B3D5C50176029E28512FAC5E685B8420890108608BF4F7D019C627ACF309C4E6" - }, - { - "key_seed": "31C7CFADD40759B0E825EC5DBAF0931812F7E2B240F3FFACCCCB0F683D22ADAE", - "ldt_key": "6D174F3A9D35C18C5873FC6C0A78D804F98EF4F131930DBE7A62C599ECF5432F58A10C2300E5B6428E4C0DC7E0510880DB7AE4FFA2791F6276B4DEFD8D5141E9", - "hmac_key": "A0856C106CB1567EECA6F20E17038971EE7B56C67E0A91F3FA065AB51A2D1ED4", - "adv_salt": "1EC0", - "plaintext": "874FB6A79D5FFC5302E140950B2DC842FA9797D2FB6034DF74EA8A5373", - "ciphertext": "13ACC4B28FB9086DD45C48D52719129E973E4C4C443C08563A52DC814D", - "metadata_key_hmac": "273BCAAE09C489A4C8F388958D8B4A9876D7C6BE02D0DE29C75EEC96A608436A" - }, - { - "key_seed": "5956A478D8411CA8A465158C2B3006149908F1EFCCBF8990317F20999AA4F70F", - "ldt_key": "4A4F052F402D0CB131C5B4FE1131AA7FD5C20ED9C2E748FD0EC1279F75858D47D648E5C0A457BCB65F222B3F17EAEF11940CD46A3A94805E51D11F16826ED5B7", - "hmac_key": "41F71CB578DBB33D3F003E8D78DEC4CCD6917236F0D9A0AC02CABAE06C2B5D65", - "adv_salt": "6BA1", - "plaintext": "FCBEC0CA4213B4B37E2DD6C8012AE01DF1E1242AA434A148D359277E62", - "ciphertext": "1E9AFC79DE49F4ECD3AEB564FFE40E4EA6A5194E61ACA01D8A9E9343BD", - "metadata_key_hmac": "BD3C3DBD20B210AFC2E33546377BBA80BC72A87EDFA13A34F8B5327C44834223" - }, - { - "key_seed": "F148AE1510BFBF000897FF10BC5B28F67AEEA16C62A21EC917C25303DED409D6", - "ldt_key": "9CD5DB4CF2C2AE6147962770007D6C55BD3590B36F78DBCF116A8B57231DE71C26B023060860768F5F74E6067C05E3CBF3F06969F4763D3D4C40AF761BFD2292", - "hmac_key": "5C8B202DCAEFBE48669513A0A1AAC66FA6DA1E5C21442061B1A88E226C8112D8", - "adv_salt": "F331", - "plaintext": "89AA70C2B5389C5D1D1FA5B79BA158237CC15347EE30F0DDA3EEB2", - "ciphertext": "8DD3EAE0D868337481296D1A5E573B37FAB61C545D24D6BB623EC7", - "metadata_key_hmac": "221ED78ACCF95FDE481AF3326411BF7E818A218507C63C819866ED56385DDDAF" - }, - { - "key_seed": "61600C7568EFE18CE65962F07F83A858A4CCC4F2F8770E6A86E0AE198FB1C771", - "ldt_key": "64803B5AEB725BE7E9541A7E7B2EAA9E43C80D6DE2A8700B89F48AC6AED908A894535C56B5AFEF66A3DAE9345ABA78B3E6363B81CA0BDC4F08809C32CA0165FD", - "hmac_key": "B4A02866B9F951B61A74FAFA06A865D5B1B6251D26A62394FC83AFC4F64706AB", - "adv_salt": "4624", - "plaintext": "312025180184B7C1B9AC2ACB4CF48AB26EA6924F5423AE7DED", - "ciphertext": "AF5C47FB013B6AAE01CD52207430D4506DF7E00927A943FCC2", - "metadata_key_hmac": "7980BB8D1F4751C04CBF6C5D4917B2CD6B6B9443777F7B5486284D0A47F305BC" - }, - { - "key_seed": "F69E622B35584B35602B42740D4FFF8DA8871A984176CCDCA91353F9D22DB315", - "ldt_key": "05D4C4E9BE27F96890EBBD83FCD4E434484156EF823501EA28F92CADE68E564D10DAAB07D442AC8591349EB228E07AE51D9F2B302F6EE44892D65423F0D467DF", - "hmac_key": "1C78A8952309D55F09B6E806824F082EB42C1548EA9A860C5ADE79B058C223D1", - "adv_salt": "A33B", - "plaintext": "6A417988704D975DC2DDCCD8823986C1F4C74B288FBE72EB57", - "ciphertext": "C37A68F6D2B29B640870300FD08DD35A5F0BC438D6CAC897C4", - "metadata_key_hmac": "601E61D942E76B8997DD60775AAD1729D85AD7337F18174DEA7D67E3736E694C" - }, - { - "key_seed": "83E3CB4033F12083313C134BB30C47F5EA0FF6A00727A3F64FC1AFA040B14E60", - "ldt_key": "8A4C959D115BE5FFD34936F1876DEEEB0836CC11B85FB29E4D914AC59D649B4C7B1BA55993C454572EA4F284718A56B2F66C5FB7BD7A0584E7206525DEB2249F", - "hmac_key": "2C4481D23836DAF9AEF1871899359EC2996F322425E4EB126CD8126A11568524", - "adv_salt": "66F1", - "plaintext": "8A7AAB07B16F67A50F62A57F62E7604D9EF3DD", - "ciphertext": "DCA7C698E366351965619E854DCE96280786A7", - "metadata_key_hmac": "1C17DBBA079B2949E4EA054E6875EDD41A8C6BFD7D0E731759549835EFD43ED8" - }, - { - "key_seed": "9DEFCDC08EC6BD9D9D5EE8B4F1ECB0D080E80BA131D8E88C7108775B8FB1AFB5", - "ldt_key": "EF241E356B44D5FD66FE56F10AB825DFD6F80A850360A0A97427793B575E001070BED7C33D520DE89C249F896DC987FCC689293F469D0264CD8DFD92E3FAB2CB", - "hmac_key": "30FA2AEAA17C3A9A9E01139DE85BE7924C4212D382A2A924593B0772C84594D1", - "adv_salt": "0BE3", - "plaintext": "2B35B8AF25D51FD081579D2CF3FDB0B66DFF", - "ciphertext": "483147378F66A935037F06ACAAB160429969", - "metadata_key_hmac": "613573DC01B49019ED0F98559D39313F00E8BBD1B8AF91F23ECCE7DE5F535751" - }, - { - "key_seed": "EB477CBD2CC5A7CD961412673019D66F91FA55E676892842B8363694A780700C", - "ldt_key": "066EA314177A5DBE76DD89A5E855E790B63CBF515E008D9D0A3CF24BF849735710E76B8453C0ED1F2D77C78245F022A6235E2A6760A53089110D60F3957B19CA", - "hmac_key": "60669EA78CCA2BC2828878FFDAE7DF7BC3F0F360A97A6806C1C76D19C90DF5B7", - "adv_salt": "2557", - "plaintext": "D35F9D849F3EBF4072F9E27CF2C8B9B5C97664A06C7E0360407A260941A00E", - "ciphertext": "FB6E965A8D084308748A5E70DD000544C2CC8BB2420426848DF29D09A57E4E", - "metadata_key_hmac": "7DFB8ACC1E2547D2D9DE93FA873D03EEB1911979388FE21B69C50739AB45043E" - }, - { - "key_seed": "74AA682518382B6E3616DA0382721CA5E8DB50F030A50AC08276969E0562F4FA", - "ldt_key": "B1A8CF202F4B3922456528E5566AB7E71E5C2A6B7FBC65EF9CF030DFF5E258DB44E4BF2D3224F434B20A14FDC7384F5EA87969F403A1308719935BC0CDAD0FC1", - "hmac_key": "6B86101900B15E6E052900939C8FCD3B7594904560FB2C99699C5BC0AE78676C", - "adv_salt": "3895", - "plaintext": "20325082990043331BD2D3A80BB87E0B", - "ciphertext": "96DDD4BFDC23FD460754FF6468E7C332", - "metadata_key_hmac": "742E4068B5CA2992EFAE77AE5D6A85FC2EE4FC629048F57A7C113CF198266E8D" - }, - { - "key_seed": "9A26B82724E2E75F688219290A5E71306259FFD45358CFCAB56820AF0AB84825", - "ldt_key": "716EF3C6A8E6D03AC8B48FB34352A3DF2BF8E585D3ABBC219CCAF7B724BC9F4A910FA552C9A7DA90943F22500AE0D795403FE3A39F5E06BF1CE082B82ACCA6D5", - "hmac_key": "8740E6B8E4AA733172A5C1D7BCCC2E38019460DF4A145A16999BF7FDDBBA6465", - "adv_salt": "E247", - "plaintext": "2C99B82779CBCF25E5023FA300044F7BD8E73711D183", - "ciphertext": "1C4E395A87CEC587FF9978A6C3839262C9CE2B1A4383", - "metadata_key_hmac": "36722D3E0A836A8E7A74D5193128D3BEA3503688DEEF566DDAFD1090D4A422E9" - }, - { - "key_seed": "2372AF6AEE19D862907446970241429B0212F31C1531817FAE55B789DCE83419", - "ldt_key": "7CD870141005EB628EEC6185B4019F0F038CD76BAA1B559ABAD2FFA079209609537914652B3FF00ABDECBE8718D0890117A3B2472D3CC0EB72F04D0FA7083961", - "hmac_key": "567E5FE57EAF46A2E2C780EDEE97035315185FD8956BA5C4D76A78853663E746", - "adv_salt": "E9C2", - "plaintext": "2693825DC42C1DCF2A10AB81D9365BF891BCE6006C2DF0145F", - "ciphertext": "61CDC03B68C66D50E063FD4C8F647877E9D3252584AD713978", - "metadata_key_hmac": "42BBECE7CD1856970D01DA3E8734A65DFAEDF457DF1E72CA3599EABF0C22C41F" - }, - { - "key_seed": "9D08404ECCCBCA0EE51E331B6D696ACD3C7176999823E2C7EEF4302FFA9BE0B9", - "ldt_key": "427CAD8F30A04435924421837BAB322F768179FBC4B784038984F8DAAD0BB82ADCE01C12C816A12BAE4623641BF1BEFBE1BDEFFFBD93D4BADDB001FE1C50337B", - "hmac_key": "EFE1F944399E5F414382AD4387C61CC384B61E99CC0435F3096E942219B91366", - "adv_salt": "B75D", - "plaintext": "350843181BA9E2B6ACBE63B7BA7D7D150E74", - "ciphertext": "5E9934E69293271897730ACBEBB03CA6FE15", - "metadata_key_hmac": "2C1CB1BD3BFE989FDACC33EE426239A738C73A16173CC80D7EE05EC3F8404374" - }, - { - "key_seed": "74A2BB7471A0592D8DAC87B95547A1C9A3E8CB1AC308DF345A4DAB559034B5A9", - "ldt_key": "443C06E1C7F2B1752B274C23C289694FEE4FA80FEA17652F10E02AFA2E2C2F36735AE72D8D83EE6ED574F60DE7E0017E4847784772E8BB3E2FFBB191804DCCA2", - "hmac_key": "09566FCA537C7633AFAA67AAD2912B0D97C96CEF220994AAF0A33D2E02BAB4B1", - "adv_salt": "59FB", - "plaintext": "605007ADD735AFA8D07288AD1667877C7F33D8B574B3664540B3119927", - "ciphertext": "C398C214954F7586A9E3ED39A942D48D42EFCC15D259C91A0C17D390E0", - "metadata_key_hmac": "E7E896615023D1769C951BBBF61C102E5A99FC79CA90A9EAE14FB4D3ECEC750D" - }, - { - "key_seed": "5CE66AB96688C6F777EF69861F715B7220C045147C30874900DFCBAD34918F25", - "ldt_key": "E7E24A6081A7D415F04EF19C540844B29837EB7AF9D97356BCC4AFB6CDAC80164A25448A12FECBDFA8E35B285A383B1BFE20E0CD0606E4E8078DD306BCB39405", - "hmac_key": "8DAD5A1D48DDC9C8496E5861514833D1B84B19787D4E1B40C78754B2EF047152", - "adv_salt": "3544", - "plaintext": "8862C2582FB4EA240D177A750CEF79C34B706E78AC", - "ciphertext": "DA89939D9BCDC1C14D85A5DC0A9CE0626522AE0E8E", - "metadata_key_hmac": "6581B9A1D1F0F4D165A0167E18C7295A731DC235926B8E410169F1C63A4DA4E8" - }, - { - "key_seed": "EFC89CAC472E5F29C19909114C58ED36EE6CD3ACB421DF6E8196036B0BB2B26C", - "ldt_key": "27260C19A758519766A2524EF2930AF8312BE757975561E9C850CBBF9EAC6BEE0432523725E7DF2B0186F95BA26B59AF8F773FE2E412D28646ADBCAFBE48F2F0", - "hmac_key": "D0112796BB95B093CF956682B6EEC9929491F2CAAE8FAD2C957BB561F178DDDA", - "adv_salt": "4B32", - "plaintext": "FD682E2BE832CBBEEB345A4D38B78BA90AA637BE16BF51D4F9CB96", - "ciphertext": "CB4790894F1FBD9598C560CCA62F478DC17FFD4A1DF3AE520C6278", - "metadata_key_hmac": "A2BCD15C733F585645D887233A53E42DB824AD128F0BA0D979ABDBDC8EB376C1" - }, - { - "key_seed": "1C9FB26139981EA626FDE6F56495710AB4F459F081BB68157D0E15818B85FA7D", - "ldt_key": "9E89B84362A0AD1CFFA71520222CDF3797CB0CD27963747DDDF30C64CC71471DAC44A480099B2CD48DFD7845A9B62451FD1FDACEE14E092A367B24EE1DEE3E06", - "hmac_key": "B83A1B3299AF327CCA3EB519EABC9024FADF40E90F73BF2F6A9B1282B31AE24A", - "adv_salt": "27B9", - "plaintext": "115B2F632D6CC15F641AB023B8A19E8E9EE3", - "ciphertext": "E19E55724D76166EAC48D7830F00605E1B52", - "metadata_key_hmac": "8C595243A2DEECF05FCB3779E5B65B89437FEE12917C70243244C07A73534FF9" - }, - { - "key_seed": "12BE8D40B5A27A6FB578010630144DB83ACE0883724A4F521340E540E2E0C68C", - "ldt_key": "89B8F5A1823B9677AB985DD4DA5A16B24CA4DE066A0973DA3C37D0BE255AD0BDD05A747766F147C09ACFE92F89E388B5C27883434D9E4BD4C67A4E30955D4C8B", - "hmac_key": "7EEBC70EB7BBE030B3010F8C6F9BA6FD1808D3740F883E4739AD3D3BF91C0654", - "adv_salt": "1190", - "plaintext": "04B822A1371E8C9DC26A697DA51A9C77", - "ciphertext": "2DC428ADB7F503967850DB31047E887B", - "metadata_key_hmac": "B9F5FF9D4B7C4C7DA4F63598A9618417D1852E7CC85CC86CCBA8DD0497DD8D6E" - }, - { - "key_seed": "F37D48DE8C8C1004B7F9551D590293B45DA71C45C4EAABAA1EFE2F28963D70D4", - "ldt_key": "11BC252F985F1F29B94903783DB6F8DFA80B41C13819507E5B4456294C04C5408AE4FD21EA7B5F2FF83CBCEB8D623BB5A6213CCD8DEEEAC85B97DB39031E6A04", - "hmac_key": "94939EC6BBF5833A6A2D54E4CC76A19CE4ECD27443B58465133DB9E8979AFDB7", - "adv_salt": "CD14", - "plaintext": "6C8A96613B5ED22D15BF5505318AC7B6B72F4E6CF78E9228", - "ciphertext": "9B0DC394A40DADABDE9454BF83DB14DF7683BF91FD6A6BE5", - "metadata_key_hmac": "28BBE4B7634E6DB87EA9EE4CB6D0D02824FC0D02FE169EB277050E877F5325CF" - }, - { - "key_seed": "30AFA37FC0EA499F56BD5E3DBFAB8EC4F8831EF774EA8B470D06711E2526D17A", - "ldt_key": "E738F03C91E9651B4798C43013DE639FF8BEAE84904EFA3B3293F52B6DBF07335F32B00CFD3D0108EE0C05EE0EA18D12ACA8FEA0B04EB082D0421F1EC93CA891", - "hmac_key": "A6E71919A74F69E525B8F6E601294484F74399B8343F4A3EE4C39CA8E884C9BD", - "adv_salt": "9126", - "plaintext": "49B90ED5973BA948D4AD48CD58B18FF9BC0AE8F515", - "ciphertext": "47FA6B4679CE70CED6D4D459BDE5A9D70CB55F1D73", - "metadata_key_hmac": "A482A818936CBA441D8002C992A4E01FAAE6CD28BA441F635D5A2FDD942C90BF" - }, - { - "key_seed": "8528A2F34296E3729E50E56A55855F59FBC902DED9D2377DCC39BF7231F11172", - "ldt_key": "0F0E76C4E3E7BF50E7D52E2AA6693419CB63824E94A0D4752D61E7FEBD0BAEC9939063AD802105C19BF9A00FDECB95CCE41E1DC198A8E496CC9AAAA8BBCDF7F7", - "hmac_key": "DF969A9D68140F537FF7FFF16472AEA113894FA265C84B75540C207CCF6BB85C", - "adv_salt": "105B", - "plaintext": "4D85C3056EDA3F063DDD092586D497446997CB274174", - "ciphertext": "4CF52656457A215F9D44683B783DA8D0D526EA42FBDC", - "metadata_key_hmac": "850891BEE1675AFC5D85978754AE1A328E8AB5BDA781B33C9614694FA65B168D" - }, - { - "key_seed": "9D0D63B34C39D97396F1D4300ECD6F1DDF59EAD5CA6C91100BA47B0D53770A21", - "ldt_key": "29FCEA9F70AFCAD6BE477C8A7DB85A9A34CA55C8ED3F1AA0013E35C3A911B3E947537AFB66A2E244B252BA1551081FE8C559478B2379A677DE0E18A22475FAAB", - "hmac_key": "EDDA408416F36883183FD95538E71CFA009D9D97DFBBCB6017B14D746771A457", - "adv_salt": "7C76", - "plaintext": "24997451E6C5935B33124846BAF868A0F8B5910F1F1A9EAD", - "ciphertext": "C322A62CBA22ACA0EF4AB79E14A58CDBC293D50C354F0148", - "metadata_key_hmac": "6EBD3E2948C92FFF55571A81FD68E1DD9A41CF9D29AED0682D95BBEDEB9AFE07" - }, - { - "key_seed": "CF3449A532950AA71097A57B4FCD9408C8F17CBB686FE08FEC1591FD5E6EA7F7", - "ldt_key": "5AFE3D6D4CDFD4D5065723402B7A2D9A7734301100ED0B8E47B2F85F7F20A56CC567F9C8456092DCB31D827354306DF52810B69F6EBF13734E9610893ED2128B", - "hmac_key": "E8ED4FC24E00C92C57D2F637E267BD016B2ABDD60B9983C554B1C183F09D84C7", - "adv_salt": "762F", - "plaintext": "7335332B8D79B72EDF461FDB8A6111C3", - "ciphertext": "3AC347CD0329B7ED01D92E95906BA819", - "metadata_key_hmac": "58ABC3309FAFAF2E0051D91743BD6B5CB364C0A2F278C818A084E3F58AD017DE" - }, - { - "key_seed": "8502CC048239779635C0C16622C23F49B587E418289430A3122100F0CB72D7B1", - "ldt_key": "BA0D750543DCDD3A505BC7FF3DF2CCDF5F911588685CED3EABA6500E970CE49DA97D93512403B037CE708FBF5BB53C725DD19CCFEFB809C375BEA90C59A4F9C2", - "hmac_key": "F815117346818F376698B4A942459301FCBADA75C34833B2C20EC53EAB6B78F4", - "adv_salt": "8C0F", - "plaintext": "19D34DF12AF59C8ED87EEBED97FFFE2811C6CD64EE3139F427029E", - "ciphertext": "93E13EE67578A7D8CB748E55889F8838F5854F5B9300D93091D762", - "metadata_key_hmac": "DD2BDA4660BD3C149F56D4F0D8F39636531398BFB916E291A925594A1EE87CC4" - }, - { - "key_seed": "DAA6AE9055EC48FCFCF0F5EEA10F9D54FC37203F21E0427F6C6F3EDBE3CF67CC", - "ldt_key": "BA1FF2973185299DC1E13C7FCD46A2CB8CF3E940F1F7B04DED6311DEFBCA0105F52BF9261A711EE436391471A7CF65A8D7182B4B1BCA9DD1321B37E93E8CC185", - "hmac_key": "007AE606E82C1E917203D48CD3B0CF7465C1E57CB55E2AEB41F7558FAF75F9BA", - "adv_salt": "C18A", - "plaintext": "34692A405DA47315781587F7FD8687F7FCA8131369096DAD96", - "ciphertext": "F17387CD4A36AD7B3FDD7291ADCEBEED9F408C1F9A1EFBC453", - "metadata_key_hmac": "BCA6BE8297D3BCFA926F80D1026F1C8DA7CCAA804CA805E5BE523B375B930023" - }, - { - "key_seed": "F25660848C48B1809AA801DC67DED952DA73A200747DA59545DAD3F17273324D", - "ldt_key": "2F7ABFE27A5D7A0BA0063F061A69E070D2581FFC8D5257B61385645807E5F7F2EB966DC84F19BC8BB31C9EFA40EEE5D684F9FB928369C76AF27371810BA4DC6E", - "hmac_key": "64F9623263CF96FC66400186A2E6F7B4ADFE15F5E184E877F802FBABA4A6F3A8", - "adv_salt": "D14C", - "plaintext": "5773E1404053FD475905049812A1CC457BC51F1567C1456A", - "ciphertext": "985840834C0AEF4921523F842CCB203E0DB581007D513215", - "metadata_key_hmac": "D96254F0FCF232B538B7810568D884DC106988419FA5ED81C1EC852F3C317DBA" - }, - { - "key_seed": "6090BF93D4371B05AF47E60940DF4DC98A56CC961B46363ECE74394BE523BF49", - "ldt_key": "5B61E2A831B733DE77A50F622F525ABC0CB299F1B96AC091F4D4122AF8048E54A9EDD97F6E53F05B382233C7D5C9BA4D1719474A1507C8F619E089EEA0C6C3BC", - "hmac_key": "7F19CEF943471DB2AAE52A95B3A90BE0983A37D02A851090B1078E983C8A86D3", - "adv_salt": "6394", - "plaintext": "FA349723D47F0E779BF19B8C517B7DCC9FE668B94D", - "ciphertext": "69C0C85FBCAAC15668AA6EB7472E613B1AA0C81E16", - "metadata_key_hmac": "8EE8E3927B0BAEBAD706C032EEEAD2E03E70211AA691F0FDF493408B17FD90F7" - }, - { - "key_seed": "EC6E0C4933F7D73FB18A934619902BFC7C3DB0CD23754D57C3128E518F5A8173", - "ldt_key": "EB02D82B568542D1F74692F528BE19910D2BC2D491144E5AFB8DBB257729CF7F21A7CBC8BB350C1FEAFFB10F4A8D3BFF379191D0647A12023AB44968D53F2F25", - "hmac_key": "33C7B177902F2A5592A3B0166020215DA76B21CCF78959D7B21E7B0A304E0567", - "adv_salt": "7A79", - "plaintext": "39E5C5F7E08B25832D023E2FDE2B412E755814", - "ciphertext": "8AA7FD7E155EBADA20E1E65092E07310C16EBD", - "metadata_key_hmac": "A81E8596D25B7470C6A1B15B34D2C9D2593E25A8873322B296BF4AB480E1982F" - }, - { - "key_seed": "2A685A402E6B4C3BA13818AC2495E6D7798163BC1AECF576DF183270DB2AC66C", - "ldt_key": "B9C393E46F60C9D1CA3FD883BE2828919E35291FCB7CF60F8E12FB544EE145330771D12DC6E1A02CF240D59B96B37093D993B2F1302222B04687D9472471472B", - "hmac_key": "62DDA07FCD2BDDC9076F474054E0458F6879516FC6E77155A12605CDD9ADFA5E", - "adv_salt": "03C6", - "plaintext": "558FCDBB132EA29FD9242E12681D3A0531DBD6353EA6011D29928D2E", - "ciphertext": "1E7FCD5BE6AA3ED1FE7C87AF62D81B0CAE76F8E62BF3DE639C1C6869", - "metadata_key_hmac": "F380B338EB5639A65FB7C2B1C8ED5E433DDB6271B5FE4B470F77784F4203B401" - }, - { - "key_seed": "4D8A9B4D23A92C4C813D63980255838C29D17A06CD5CAB47737C926C0E5A5F2D", - "ldt_key": "4C1BD292C6F1D788264B74C6A7D50B56D6337FE643197C7B771FCA218A3FBE612B767B9A132726A45072AD08FE5994BEA3EDDFF503B56985CC72016E263B7EF8", - "hmac_key": "D60975FF61115BBB89BDBE3BF84B3A12019F754356FF66F2F1714A63201805FB", - "adv_salt": "B3F8", - "plaintext": "7197A958EA9D9D874353F3A5146BAA614A2C61A5815B5920419B5580", - "ciphertext": "D516F8023B411DD3A2E21553B7F0DE0855D8E81BFB0283890C902BFE", - "metadata_key_hmac": "EF3BA4E20A8112744B960DF77FF046FE9EA20C55115C088973624E1E3D8A6B5B" - }, - { - "key_seed": "C9C566D3088648DCE86E7DA80EB9564616C6B173A01A00FF7C0CF37A01B21831", - "ldt_key": "CE038C13C852A8B6CDFCB62566A221B77031106FE9FE01A80A7EE530274839461BC90AE38440E97A02DBB6EAA332F069DDD3989ACBC3897C05B9C2D7F04FDEE7", - "hmac_key": "0DAA5072EF22712A2B4170BD88D19A8E4A80A96BD57D509FBC204E79274BCDEB", - "adv_salt": "153C", - "plaintext": "B54CCE60149E29D8BDD9C6641E1EC88863CDA651", - "ciphertext": "2CB51396470FDF4CACB8493B83B1E5EA0ADFC573", - "metadata_key_hmac": "806A5DB9A3ACF83345C3EA3D45DB135BA9007A923B4C7E394AECBEC2F7BF2190" - }, - { - "key_seed": "4EC98D85F72FE8D7F6D04D4A202BA3300091FFC4B461EB93C286B0812AF56098", - "ldt_key": "D10CA2BEF1B09144569A8AD318882FEC986B13902CC6C8E6FF3C3EA9158EB81F1E5567E6C3B67054A80866A5E2A64EF6B20FA825C37C882A57C785B5F8FED8EE", - "hmac_key": "C50B0B4F9B844EAB7F75EA81790DA6B9202DBF09D588D3AD0E09F3C9C3153217", - "adv_salt": "8AAF", - "plaintext": "3E67656A66F8FA1CBF63B1CD162F39E4E99B0B837A", - "ciphertext": "340A53833B28EE6D68A63B742E153CC9C15E5EB061", - "metadata_key_hmac": "18094118719C7A553CCD7D75FA733B2EF100A0FF3E8CCAD62CDFFA7D839FB8F6" - }, - { - "key_seed": "9A064BAA308923176299AC838F59C742FAFCF03396754384486A643B619CEF78", - "ldt_key": "799D31477FE6407751C233E8EA23E574B2C58B762195EB9BDDBCD2AEDF58F11C04768CB76CD9822E9DAFB0B74609AE4E91F67814085E19D21AF885AF079F98A6", - "hmac_key": "87FB2C5EC3426F8F8118CD237AF67A2D915F8E51B31AF731B2C53704E1850E8B", - "adv_salt": "5482", - "plaintext": "97A88CDAAA31ADF5F25DF156A65263EE2E6AEE7E19A0B07D509C7D", - "ciphertext": "D15B17B9D142E3B8D2478DEA14853ABD6D60CBF50E5C83A9558F90", - "metadata_key_hmac": "4A17C1A21242275D9FFCF6F2197B0F5A92A4F42D7DEC63EC91C48B33219F68B4" - }, - { - "key_seed": "6E61EB596A2E5C30289BD0D62DFB6BC79EE546DD4DBFDF087426F31DA395D1AC", - "ldt_key": "8A55C3EF7748594CC2C7A624DF2843D603BD7D03383F72246BEF686FB052585E32E192F9FCFA847A2443C23395A6BC71930B1A5278CF5459DE5C61CC8A806274", - "hmac_key": "91741B464B1A30F832F2B1FFC94A0F4944A34A73160BB4A965466566C7FBA919", - "adv_salt": "66B5", - "plaintext": "9254F8FD7DD259B5F8D4ADB4168F6D9E9CC260", - "ciphertext": "7A19067485676DF76D868F5548E81DF3F7B218", - "metadata_key_hmac": "4889130DBBF07E75A1B864DE9D1FFF7C9D4645269633C4E484095D771C453A38" - }, - { - "key_seed": "413C29D326C97973AA72C9445AF1490F38A1D91741E7A5915F6D2546FA73780E", - "ldt_key": "74B9A9EBBDEE549D75C619F19CF5797E58B71F29928E79B7700F7DDD02B2187166B23655B2432CFD057C3B4627F446CED8604D0306C61340C977139F6909C12D", - "hmac_key": "17592D7D59DB2D61CC93FA408AEBD68E9B6AFEA5E9DB8041B4F661059588CC05", - "adv_salt": "46D4", - "plaintext": "EC3CCD49517F7C4D28B7060925DE6EC61246CD179E515057BDD2", - "ciphertext": "D0C803AD7A7CFAE60D0AB2E902B4B0B264BAFDE23FF285822C34", - "metadata_key_hmac": "A6A8A38E5899DCBFE53F8C2F096D14875C28B9F17469432C2467918B5124E289" - }, - { - "key_seed": "34D418B85A3F83C0C9161C9ECDE9F085E660C06B875FB09E7BD5DCFEABB5E716", - "ldt_key": "2EA9F9885172C679AD31E64BD2101593A448C95BAE3ABDCA3495D31E5FC75CE5F209B6F1F73F108A77004A51700B79CA2748DD29A805F057022057DED77E7607", - "hmac_key": "8DC19E5A9A7CB1008BDCFBE14906D56B66899D26E54925B372310BC02C1199ED", - "adv_salt": "6BA3", - "plaintext": "D08B3CDBBCC618CD992980B3D22B186DF94C0A646C762FFE544436B8", - "ciphertext": "632A1D66239EA12E38F2DDCB9BB0ABDB10189ED3F173B5F494E508F6", - "metadata_key_hmac": "C505EC0EA2BD905D96391B48B78AB0AE823AD75F952A29724984CF3C38EA2BBE" - }, - { - "key_seed": "2F46796E27F2E5FCDF269E2B1BA585644C7714D4D3BAF6B5ECC61882569A4C21", - "ldt_key": "8425986BD785552A56CD689EA8AD2A05E3922710265F5A68BF83A2AB5655814A20E4850CCC76DBBDB38F1A61261142CDE744F4F9943A3D98E76DB2182A4A2628", - "hmac_key": "7D33A33F4386C4586C035A5E49BD1F663973A7297A7B8E6FC8A47C6D2C1819EC", - "adv_salt": "E2A4", - "plaintext": "F800EB3409FDDFE1E82DF9236A7925C5A5B4CC3CBFFE7A09AFF1", - "ciphertext": "EFE31E9A34ABF4880F19AB67C464448EF1FFCEA3A871A616C208", - "metadata_key_hmac": "C84CA1DF801588E0F05FED981BC716D718F712EB7B851157C5E9A671E8C1EDA0" - }, - { - "key_seed": "9E289AC48C9757AD7085A31E4F274AF7343434BCAC94298F74D936F45FB13A5F", - "ldt_key": "B53BF793638F38A19222BEDE90EED4D5974D321DB66100E4E97F23C6E576C03F8D22AAB72CAE5BFD7174B757306C90481C29D843AE3D463271E575A8A28EECC3", - "hmac_key": "316CF1F279553D1F01E4021855F2456ABD87D17C4B0799AC59872B15F5DA2236", - "adv_salt": "28D1", - "plaintext": "6012835C1BB1059E313C7129CB01E73E4CE9BFBEC35AD1902591CA8E249D", - "ciphertext": "8D5A0749FBF107D3EBD02F7C6D6A3E1660A310CBC01982AAFC53B9A33518", - "metadata_key_hmac": "5B3C970E2CC40C1C010AFD7864B17662D968918B4560BE222A6625AF69663360" - }, - { - "key_seed": "41A099C5D66CB945FD237961326E7E7D3025A2AD4AFF31BC560677315DE6984F", - "ldt_key": "66C76AAC504BA1EB783442279B852275DB61BF7411A16B54DE7BBFB36E046836C24D4F21C18AECC1B7C07CF1B8637F2C18D0BA897290F24CEA0ADAD7EBF3512A", - "hmac_key": "0EA893132D505F883067D2E126DAAE91CAAD6815FC157458D5060D9FD486A7B0", - "adv_salt": "4DE3", - "plaintext": "B1CF8B0EF26BC648B580B8319D0B7A1747BB7EB0AA5E3408FECF5052A6AB38", - "ciphertext": "0EE27C2179E912D1E3B755D7665A6CBF6CE5DCC2782342329B216B9710756F", - "metadata_key_hmac": "67CFC854F10DE020F9367C3E4A1707445D77D6BE0CE9608F0FC7512DA64FA646" - }, - { - "key_seed": "22D103430AD13F0AAD09237D0956AC3CE7D346692ACBCC88C6B6169974A6C07F", - "ldt_key": "663EE65D559972B0E5FD2C5D06A705B6AD5707E650FA56DD6E5CED45AAC0FF6953B27FA7E54D721195B17A24235B08D276227A773249962C7410C467CE9B9308", - "hmac_key": "68B75BCD7A56B9FA87E376894B2B12206A4DF9036AAF59FEFF70A3E5BAA0D12D", - "adv_salt": "1A9A", - "plaintext": "569FFA5167D91F964AC3CC28E7E21B9C05B75CCC105A", - "ciphertext": "06F069614B544A4C62A1C89E84DA8035FF09C11B31D2", - "metadata_key_hmac": "53CBC54822859D915FD7611D6666C263A56662A6E4A0DA8C5D47955C8E6EC82A" - }, - { - "key_seed": "9680FC88D8C9AA02F5F51BF197DFB26C081662A881F2E25F36C93C39ADF91EBF", - "ldt_key": "7F2A76B8E85178F52A34ED59FF49F22EDF11B692577F264280E48B47B5D0CA31241CC4745E0EB168D289C8C038331AE7763FEFD20BEDD5AE0D91182151630B71", - "hmac_key": "138182688470F6442DBC195B17130D7938518F6BC83FA37ADDB8D27A02811988", - "adv_salt": "B0DC", - "plaintext": "B2193E84A9AAE8D050EDE19F3FEF625C635617B44DDEDE561D086F73", - "ciphertext": "86F68E13C8DC80EA41E714D32F1F740605838006D7B0C03E71C2F825", - "metadata_key_hmac": "5A315A06B4675F86C422B31DC8929678BB2D30F88AC0E4718AC1DB0057BF2504" - }, - { - "key_seed": "788B543F104FF097140DDAD8E3836D12A8BEE16E5A016A8DD663F46D5C8BD7D5", - "ldt_key": "3BB2663D34518529E4DBA6585CFE7389933B578BD555A1513AE34A22613198FFD83167F31CBB07B61E01D3B3187B7967AFAFA4BE079244EA840FD1907921C831", - "hmac_key": "7A013F5FCEDF4211D8AC39347A6EA17EA1FAE86C391A3D532C9CBAD3569868FC", - "adv_salt": "0A54", - "plaintext": "3868F0161F239403689EA195843E068F25BED2C4", - "ciphertext": "07C2B953927FDC86CEEC14E9785E8309ED048A4E", - "metadata_key_hmac": "21884989E2EEB3E60CFF4470A6DF3FB36E55B1377C28EBB03B84E1BAB7337F0D" - }, - { - "key_seed": "3859912F98565FBD72AAFD02C7241AC31C65B0D8B3C3BE15A7C5ABF44DB123D2", - "ldt_key": "C943FE69AEA239EDDA3DBCA62B2D8C402D9CCB6A643F25CDF11C7BFD36CC8C612C950F7A81891F13495ACAE4CD08CD2930E115E0F9D0BD637FE8FC6785470D15", - "hmac_key": "5DC5C8397BF983D109283C156A954FA5DC1A50A10DC43C04EC4D0D57A905DE88", - "adv_salt": "9D1C", - "plaintext": "435233CA5EBC5FF190707E5FDA434A17EE19C50B2921F4", - "ciphertext": "DA361F78A91F12A55078769C4B1D11B6310C6E140C64CB", - "metadata_key_hmac": "E0FB801AA32CF13BF47E00050A088DE6C53A5E9E40B484377A9E62E4EBA6A265" - }, - { - "key_seed": "16549C7D135CF031095B1C5E847BE71C69AC674597CD636A6E5903AD35B05128", - "ldt_key": "3242D94DFE7A36E6FECAD6F5CC58454565D8574DC843658713C6494EABC5C7CD7EFDD5420EADABC5A561CEBEEB379956CB1351EF83711B2B2A40D7FED6C9D6C2", - "hmac_key": "BAD2D225108964EBC04DEF61B9EBE88511C3BFB649D7F6B32EBAED20900E4DE3", - "adv_salt": "9C64", - "plaintext": "8B1B3CF0B247C961A552A4D9E154EBB59317A7A7B89E60C16842744453D1", - "ciphertext": "FA710865DAFB0B545E82A91F73A437AB9B8F7209292B9068F3FDC8B6D4C7", - "metadata_key_hmac": "5BE78832E7A926F05AD30277FF85BA56FA36DAAC13A97B05F8FF8A25B375188B" - }, - { - "key_seed": "FC774651E46E37F2955FA37BC0ADDB4F71797DF194CEFD1082509BCD139C3EDE", - "ldt_key": "7E18FA91251EDCAE40CC43B2B3213E15B12A38A40CBB1F2A11D665F419A001D6A98055E49A52DD9A4E9AC913AC7C029C624B76FE869C242AA91269FA5A0E0E7B", - "hmac_key": "8E028AADA56B355B3D18FB1FF73A0FB97959865B3164025E54312F4B09D9501C", - "adv_salt": "B6C0", - "plaintext": "48D81A930FBA128969438F5B9181D829B3932E755DB87658C9EBC35A1C59", - "ciphertext": "7AC37A8A4379B10518D367C4615A099C600AF54E1370FB06C44FC88D26EA", - "metadata_key_hmac": "B2E406516B8892B19E61FF0C99A32C65F20FBD9D92F9833C8E7414A40E1997D1" - }, - { - "key_seed": "9A68CE290FDE2590F423D2B173D6F700335D4935BA88EFBD84CCD9B98D62F148", - "ldt_key": "1B13E1A2580433EB1EF83845B35C499643F2928B55A381CE9ACD29A258AD325CF21858C9A354013DFBDF322F74B728538A4EAFD696531D7F80826FFACCD098A8", - "hmac_key": "31C2184AB947A9D39C101965EE706E2790FFA60DE7DC789597C52E3A3336ACDA", - "adv_salt": "F2D5", - "plaintext": "96A54987A54B00DC6E045D18FBD129D1DBDBB748BF44FF26BD867EC76203", - "ciphertext": "471A0CBDB571FDA0A7495FE7967545F2C661A4CC418DDCCFCD241CAD19D9", - "metadata_key_hmac": "E050224F87E969CD4F1B18AD5B19C2E8FCA68EF8965018F15BB1A7CC57EC9DCF" - }, - { - "key_seed": "71284F8BF099909B5643B6295CDC676620A79F1FF4C37CCD044518E16E05EFAF", - "ldt_key": "1E6857D4B7B58BED2C299CFC0A88483BAD0C027F91C94975950A2BAFCE86FD399D614ADAEAD9D3DB80B6962520C05D5D68F99E6E9381DD65BB873DDC9E173061", - "hmac_key": "502BEB8C34A8A56C52EEB7B1F445BB935514D8D80E836A42E8AD762742CD2D0A", - "adv_salt": "C790", - "plaintext": "BC6AC409397647D14E11EAE3653123A1", - "ciphertext": "D3BAEB95A9B1DD399BC7572E1386AB62", - "metadata_key_hmac": "B33A36BE15F25EBA65835FEF8A548F283B2A57A681234CAF2AE57202D28976AB" - }, - { - "key_seed": "DB32ADA65505A45781EF4E0D307B06911CE24C29B885FAD11EB653CEAA1801DA", - "ldt_key": "CD71C2CF5C35511A1CC36EB3B3A008D3D16F2AE176C273DDF9007064E71B7F16D64437BE221402994F1D11A36C9743D5BA8B4D2688052127A9A9C7AE34E2448F", - "hmac_key": "505F53627BB5E3E1443FB7A7504FDAB686EE6E8201F4DA5D59174BA77D10A3D4", - "adv_salt": "62FB", - "plaintext": "1D4D91AA7001F510B7708B11FAA34F6C2D3FAFC9A89666DF1CDB57366C19D4", - "ciphertext": "31A32EB26FC116911AEDBB2DECBA5FEDB1B8E8A3F1D6F226C2E0FF4480D2AF", - "metadata_key_hmac": "A17B8A4FE29187A40645F046971C4255F7287CF385504C556F044002CC46712E" - }, - { - "key_seed": "4ABCC9B9953A6A9924115ED9E6F99D348B3C511A3623831B0471C33D7DDF2A4A", - "ldt_key": "B7F79966BFD45B6FF5B21826DD00CD71EF406E655F9212E2AA0F1CC651C623541FFD68C2345BD368E72869DED95F1CCD8F165581BB17752C62C3569170DF6C9D", - "hmac_key": "59888DEE165F45DD32A4096222BFE29A04BE79AF4702A99AB1AC12CB7B3E4789", - "adv_salt": "DE75", - "plaintext": "3DFBC7C04B895DF08DB17B04B187B53F34CE3F", - "ciphertext": "8732F4FCDCF9563AEB5258A3F6D9B12415C3A2", - "metadata_key_hmac": "439C89FDDE11E70F2CC3B886CB1094276C1EE5117BDDDEDDAA3EAFB3BAF1C1D8" - }, - { - "key_seed": "2B1BEEBB2E17EB4B41F1D02DD6994A9E79115927C2FEC52843997C0E9B7A0857", - "ldt_key": "79901D166785D10371F5EB9631ADE4AED6F867AFB62BCDDD078A8C77ABB042A178FE9BDA4ED565D6E84CE1B55BA75421236FC8314ED62A3381DFD063EB85F438", - "hmac_key": "C7EC4159B8F69E7B89EC24F6757CA5B24D9BD7170A204E87C40ED79310545312", - "adv_salt": "2FA8", - "plaintext": "9D26AE2C24BAB406087FDF03F60436A9AFD891CA6081078AA6", - "ciphertext": "B6134005E78E33683CB7D972708848E3AA5D31637C90787593", - "metadata_key_hmac": "965CDB488C354A11737FE7F1E387BD788E943B26CA330634693F2827F14E150E" - }, - { - "key_seed": "4406B55C675E896426783D5CA64576B18831889D891151F3C8AD4A309E73E2C4", - "ldt_key": "CA0F77A19D2AD1801BC76EA1FC100FEDBF17F82F478CCFEBB7FF5AC980567B4F9511E3E57C7FB8F097EDF5427000E5C895751D60692F7DC929174DD260948770", - "hmac_key": "EBCDA862E6B338B9802FD70A00BD7A171FCEF676BE3E613F778CC8375A64A702", - "adv_salt": "BF33", - "plaintext": "7E79CF2DA280607780D4518EE475E9AE2015E7050A1872964F06", - "ciphertext": "A229D7376013646117AA78B4B7436DDE99B80E64C1738F30E022", - "metadata_key_hmac": "EFCF0CDC83FCF0E287F11795E0D11CEF911A1D729199AAF27D9037262070FBC2" - }, - { - "key_seed": "8190B60B4F263AD0661EECF3CF071A145AD22C1F04275CDEFD7073494F95F315", - "ldt_key": "31B1ECFF18C4976AB3E81CF8F04A2FB0DFAC8FCCBC9DED641520DA9CC82EA4A33B33BF8E5F45AEE2BE1B02AC46B8119E53D4AEA80AB9B5F37263905A64BE6141", - "hmac_key": "39B16AB474D1CEB8F37310CB3F72A6FF1E4B41E7FF89ED796B5B2C1AE38C948A", - "adv_salt": "C79A", - "plaintext": "3A8AF71CC6C5BB3C3D4B954C28F69DBBBE47", - "ciphertext": "2AD075D01B2F8C7653DC6446AF981BE95E97", - "metadata_key_hmac": "EA1BDF5B226105130FE5D85A030F7E045C11B238FC0CE0C3A3C45EF3274BB239" - }, - { - "key_seed": "F58783AE9ED0E7AFD00F12BDAD1ECC6DE8BADDA679101B84C36F7B2417D3CCA0", - "ldt_key": "5595C8AB388892CE3EFA50C5F0BA40F1C646B775D7D1983AAD72687749A9933ADC9580566FF2A90415F49F76744CF1703C828AB6933867045EB54F6B76F5F15E", - "hmac_key": "71208853D3DCDB60D3985FA4AB2954EC18651BC144AFE10820274A542AAD2D44", - "adv_salt": "E686", - "plaintext": "9E9C0C848A6610881B438584C9CB12E61870", - "ciphertext": "7CAF839B2F82A56DB9880A371645734FE734", - "metadata_key_hmac": "7182053162E3D3E19349B309FFF978EEAFD47AFFE57D9D37AA6E6561EBD55BE5" - }, - { - "key_seed": "B46AE555E1D0F018788D0B14C8A7C3B722980BDDCC417DC94B852493469A4A86", - "ldt_key": "1FD8F39D1665AA7F3C4C01F0920C99B8F754A49EC3698175D55E857C660BF188F738071E29C11C7DBE5EFC129BC5462FCA468A0396B2992C345FE9F660B0DED7", - "hmac_key": "DED8B1817D753047D90F39EF7977BE3F2D0840B29A3BB54C98978321F68F2C44", - "adv_salt": "AD78", - "plaintext": "0CB40F4D7AB70FD940CBD41D48E5510D71671772F4C7050D1A", - "ciphertext": "BD4D7F6E0249481917C2B209976E83580D4B4AD8FC4E60F515", - "metadata_key_hmac": "AD3121FDEEE62EBBCFBEE2EEC8ADED78E867F87BA5238AA6DBBB85852BECB0D7" - }, - { - "key_seed": "DB9DD2F4ED734844D261A336076358202EB6D828B99F396B19EBC133781A60A4", - "ldt_key": "F091157C622B58661C92D079FD5FA8C7840ECA44CEADF634E2BBECC1CB2A42D3857BA8568AEE69CD92852384CEA086FFB45DC79C38813FE203832EC0216D03CA", - "hmac_key": "B856B2988B484356EE19E32460774A2A4220D4009FF272732C13B70A839E19B1", - "adv_salt": "8A36", - "plaintext": "C7C38D01C61FE412DCC84D910EC3EB7D4E44F4DA11", - "ciphertext": "D2CE35FBD1F5D2681B0EF65CB1006561480D39FD95", - "metadata_key_hmac": "B38B088F5600DD5EE317BB271117BC516E7BA5CF39AF1B6AA53600F77495AA84" - }, - { - "key_seed": "8B51FCE2FF95A5F1E20138E5753B1F3C7E6F43E73C5CEB4495CE434CAE4EA356", - "ldt_key": "4323C8D74660ECCD2718FCF59FBF4A90643E9865C1637877BD3E40C470EBFC68B76834820A5B5D39BD1476D45482751EC918ACE5303627EF6DED59EA36890C0D", - "hmac_key": "25B8CFCA31C675CC7D8B74079C9CDC20644CCDD2E47D6A6273DD312EE4362A0D", - "adv_salt": "E808", - "plaintext": "F841AAB108AEDD72559A3E3015522D848C5751", - "ciphertext": "9A9653222FD23F8C5B1B9D600216899D1F8AD2", - "metadata_key_hmac": "31DEA95385C804AB3D94FC4FD6199A0947155D771DFF0FD1FCA26A9786F04ACC" - }, - { - "key_seed": "B4BEBB32109FCDCF93551DFFF147D74C2277529C90C37A434A6CD01B2D8E7B51", - "ldt_key": "0CD0A7B2FF0588BE56F1292F2569AB952AB77EDA27786B25858A88A93E13DD45096ABE153F6B96E4D6382EB7A4D85F47BE6408041A86220CE687AA87F63BBE3D", - "hmac_key": "5C1E37F63AE477877C96D0AB37269EBCAB560D2542024A2AA14FFD4A3F23E8D1", - "adv_salt": "8CC6", - "plaintext": "118914D47B6F4A6285D194ABBC07E85AD3F8459FA8EC23", - "ciphertext": "B5BC04924C066803A5238772BF969141E84DFCF09A3402", - "metadata_key_hmac": "0A8030F9F7AE9F0016312C3F766A35A28A7DC4827F9FF54E927F66E1092601EA" - }, - { - "key_seed": "8D36A709B972F31E6C65F898A6C1DDBA994764637C16DD7F3F0C01E25CDEF4BE", - "ldt_key": "EB64426C4879E69CE572204C3CDE9645BC12F97DFCC08A2F833FD4E897C8A949E138DFF41D9DF6A6F4909C96C6DCF18C6E142A983302B4183160130049EA67FA", - "hmac_key": "8B44C8C6CBC5308DA34EF69481C0E55CD8BCDA0DF97AB72D9FE32B439F32A3CF", - "adv_salt": "5650", - "plaintext": "55BB5DA88116677E60C209975D232FD18228", - "ciphertext": "505D8431CD5FA2A8610E4637ED1642209E18", - "metadata_key_hmac": "E6ABCCFD7722490F5737199427A5AC2D9590857E4E51A88F4D791B1E618D0989" - }, - { - "key_seed": "B4887F6B359B821DB4D60546C6294EC221BDF666B4196BE5BA61721FE0B28BB8", - "ldt_key": "35CE72EF7251ABEA55353EB5BC0ECDA64A1168704A02640DCB5ED01A095152A0DC6F2224A8881E3553B80531B2CD69C18A4C341D968FE13FCA035C337C3CCCF1", - "hmac_key": "04FB7DD651E419A2910EB55CDDB1BEC0C1ACC55E399E32A187302354DD27FF30", - "adv_salt": "F882", - "plaintext": "0DCC4777A5D21C65AB07BD1CB0F012B2", - "ciphertext": "C6ECDB9157DD9B51D7E74F04DBBD7DBC", - "metadata_key_hmac": "AECAC660CA2ADD550FA35AD8167A559FDDE6EA2311D0F4EDAFD2D5795941B925" - }, - { - "key_seed": "162CAD94DAD9F52B1249DEB412E9F5AFC7CBF5B49FAD17B01DC6A826C3C2CD43", - "ldt_key": "F4E47C120FBBE55A36E57FC19EEFC68BD6FDB905A48BD705FF183DCB8A67FF7A8B5C8DD239C3E9E0EDFDEAB0B5E6721329315E9C7592B9294E593C962130EDFB", - "hmac_key": "333DC195EC74020A025C45A88511E114B9483EBA1F1E654E10A2B44CBDD7CF26", - "adv_salt": "5392", - "plaintext": "978C189EFE7051EE0E5C66D3A14B95DA9C", - "ciphertext": "3E0821E933EEC846E07092486FCFB5B4AD", - "metadata_key_hmac": "DB7D14EF5BA498D4D1A98CFBA45BE5A666D707537417EF58C86323EE8871C584" - }, - { - "key_seed": "65A386C3B6117EF7447B253D30A4C6C1BDEF6AB3C3900CEC59F1CB57BCD7224A", - "ldt_key": "AEC938648C3F12B794F472AFC642952AD3B54D3F7D2B87494D2789613D15F262C8288ED55607E1734FE46BC712CF233AC0AA42F4AE137534B3AD7E42E7313E7E", - "hmac_key": "3C68EB194AF430833AB155780E977E77666A159AF096E1807DF7E7AB90C48060", - "adv_salt": "0109", - "plaintext": "FAA440F3974DF45683059B00DA301B02C4", - "ciphertext": "62FEC26B06EA10192D9326C4B7F8DF9EDD", - "metadata_key_hmac": "08F4014B16123D25EBC9F7A37916130B60A1840BEA2B3B0BBD2D3BD0C55A84FD" - }, - { - "key_seed": "F4F8F73D94974410827D1E45567FEED1B0DFE93CF5E6922FA271DC187DC55C6F", - "ldt_key": "B2D62C5A37C2EF10A13311EF791191560702D2D4048BBCB51EA05CF1C96436953D110C0FBE0BCBBDC2B10FA0B9A151A5496D601F0C8553FA09ACF96A85F036F4", - "hmac_key": "CB6D166C67FD8A2F15B6BF41A8687F297FFEE73742E2DC0188FE786F9E91FFCD", - "adv_salt": "B7D5", - "plaintext": "9841441046BD14AA74C6270768924FE80F1A9E87CF4FB58303C244D677857F", - "ciphertext": "97DAE3E3E2E62618463FB56A8992B6DCDF75C243683B889888241D9D41A9A6", - "metadata_key_hmac": "4C6B37E6E227CC21C346AB4949C97F46449D1B21DB5A10333DA96825979B285E" - }, - { - "key_seed": "8DBD9E5EB9C9EE1C09BDFC5F27A81AB3D51EA20257FD550B4928745D4B9EA8A0", - "ldt_key": "00812DA977303D35CC113B82EF7145F5ED0B70DFDCDB22E34A930A960DA8AF57B09CD331FF8B8A523482992A5B1C8292AB7BB51C9CC990E768C76477ACA5C5FB", - "hmac_key": "309D2CE7A6C72A0EA9932CBBE1C40E150C5F60B29EBB0DAB37561B119BE7F6C0", - "adv_salt": "FBDE", - "plaintext": "085A47079930F5713309A6D762120C5701", - "ciphertext": "3888221A4488F4B6E106F38AA7B3A198C6", - "metadata_key_hmac": "A3ABD92B5808B5BD09EC1D2F383C82A77E5E36D20E7E2519D65CC38798960BBD" - }, - { - "key_seed": "36B5FEAF45253E5FD7A3F2F2B75409EE518D5C231CBC6BC5642C94EF4BBA28A4", - "ldt_key": "0005617531C346C2C728766D9B02767D5198F7A93262C134079F3F26189F32BF2A6083706BB77BDAF78A9785F7CBE319A5E82B4BDCFED200ECB70E87B900A9EA", - "hmac_key": "DC4A9845768A5152B8B8795CFA8DFEA3B4B703303642E316D180AFF90A0DAD93", - "adv_salt": "74BA", - "plaintext": "9C499B714A71C5BCF065F99FFB91E98D7E3FF1F46964C1317D16C74304", - "ciphertext": "9560CB581FBC1DC76B3C9BC40F4C166CA771D3D5EF1BD35B3868B1C0F2", - "metadata_key_hmac": "E1F0037788E36AAE391E5644E9FAE133ADC982971DBC709959A05A8F4F84225F" - }, - { - "key_seed": "156BABAEC767C47FFACBA5F54BAED7E8FFDF0FDFDF197A0A3A9E706D82E3B6F5", - "ldt_key": "40113FE72948F108C8B21B188B0412B4CF7B27472EF5B5D9CA7E637ECAA5EF3435E9B2B231B5617760CC926417CAE64C84E63C94648BFB076B9601E35A57BD2B", - "hmac_key": "3D06CD322ABCF9994C4349F30201E8B30762ABAD01821FAB80BC8CFA89A98917", - "adv_salt": "0272", - "plaintext": "85DFBD49AAF71A3EF9B243E1ABE18B5A949C7900F197DACE4F07B433E3C0", - "ciphertext": "EB60EB75B7DF32C0E527D498AB9FE613BCE84338DAB068CBC00880156F4F", - "metadata_key_hmac": "746279DB37F08D7827E9A164802466DC9F19AD5D23C071F5B1D84FC36C65EE4D" - }, - { - "key_seed": "A7AA0C3F40BF3F5F82D329484E85E847AEE8F6C9B6D8F48E886EFB95ECA3A3CF", - "ldt_key": "D81154AF670C91CA943B511D8881825912BAE9E931DA78CD284D6B1B66D9F18CA3BCB59417BBA6DB89AD244DAD51BD74EDEE4FFF1647E822379CA2DDD01C85D0", - "hmac_key": "647B175FC721704E7F3914355F716BD4CCF89FDC6B40F0652D6991C78D7732CD", - "adv_salt": "094D", - "plaintext": "F1A7EF9EBE87F17ED1A9C5F20536F0B1", - "ciphertext": "B796373F6BB4CF61B756EA3573BF3C79", - "metadata_key_hmac": "EB93BFD52DB4FF7318E0347E2F2DDBC349D43B30505598BE5A2FA554A001251A" - }, - { - "key_seed": "090646E72BEF838D0B591084CF7F200A2AE04CA7EAD150A07067DDE54B44FC8A", - "ldt_key": "44FC3318CFC2E466525C3D188C7C7C50623A9B12BFCFDA454BEF200B22998F0896FC1A03707908D689D16CF295BC617D50093ECF706FFAFC10B959011E21EF6C", - "hmac_key": "A62908D0222822364C78A9D3176E33C038722B18E2401ACDC2EDE95DF85B0964", - "adv_salt": "457A", - "plaintext": "E467FD1BD1874BE21617B0813C3B8284C26D", - "ciphertext": "A0FC977C5F13050F6007C6FBC51935CB5F2B", - "metadata_key_hmac": "65CCCB5065AF7CD4CF8ED8550899224BEAB8D36C9070EBB2F838FEF09A52708B" - }, - { - "key_seed": "496478EB6984480B951E25F65E9FC85845B1418D32F55B4078B5419072EC726B", - "ldt_key": "A55A53F3BC4C077F42460C09F35CDC2777DDCC57BB39B2015D2A14EEBD1F34ADC7F50F4FEE2EE3C32EC76C6FC1A7AE7BE0840E925DE517DCB10BC6ABEC6DD57C", - "hmac_key": "CAEA21DE3A96C3F4C225249FE01A3F03AC650FD5603F444F38F3FF6FFDA15181", - "adv_salt": "C7DF", - "plaintext": "F0E1D9134AC84E5920EA442BFB97F4E7BD6430876E7756A282990768785222", - "ciphertext": "E8490FC5A4D063F15F1A5A533A90B49B81F053815C48692ABCCC953FA9D4AF", - "metadata_key_hmac": "BB2E44E96B5CD4C949B5FA3617BDB2636A5028F6E8B319B0A314E442EB6AB274" - }, - { - "key_seed": "81769F513E7F04A5F46654FAA812CC261445F811EC5C51B02108EAC1A0113C4D", - "ldt_key": "CEB48FE083A2C24B0355E25C01EDDEBCE9A8CFE49FE1B1E8398399451457ED7888DA4FF7288717E348EE66035C118575CA2E370EE93A4B105DE78606B94B0A3D", - "hmac_key": "517E210C373009FE4B346AA7542BD6796662EED0F43D24A4E2BF805FF2B23767", - "adv_salt": "316E", - "plaintext": "7B920A59980B213E011A05BBB148B3D840679B1B49EE260C9A", - "ciphertext": "E4D3A9A7A8025C8AF0E94AE7683637BE2F15F4E6994F75F336", - "metadata_key_hmac": "EA0ACA6C565FB416FC16F0D4D0152B6EFE6271978DAE0EE97D3254A5F3092F2D" - }, - { - "key_seed": "2CEDA9DEF003DFB2170584F5B4CC555B00BBDF31BCFA60365700772D40CD4DF4", - "ldt_key": "A63B02E2C5923639AD6E668FA63075665041D82BE75EEF2B0D005EC029923BB3DAA1394B776A71525B1605A056F8DCEB50DBD7ADF4DEAD271D5DA38C1D490DFF", - "hmac_key": "00C3B8DC4F7A9DDC6883A0AC253D4F62246C8DED8D5C7C5A816701A55392AC79", - "adv_salt": "64E1", - "plaintext": "568C456FF7E72EEF51E1DD3C89B84B2C60D10774339F7EBCE578", - "ciphertext": "DDC02E7EC002DB5EFC89E7BACFE18A4176FA37E7A8FCD066151C", - "metadata_key_hmac": "C2D87C8C84FEEA8B46DB522C4C5DD82DC974532DE5B0C47200A1CE4452018821" - }, - { - "key_seed": "E586C7755F84369EE2A78A4CE017880ED73950F49BEE1B91FF1E284BF56C2AF6", - "ldt_key": "6BBB5418A787E5E06E2949E4D7B143931CB793E98FDC2E9D733E2C72C40C5AFDFEEE10FF5AD9A8D9BFFEAA49027397BE675D63250698206F4A908244D6402418", - "hmac_key": "A5F151C706A0ECC923F706DE2A1A458760C251581609478B9F70533C39EF3D55", - "adv_salt": "2872", - "plaintext": "96C459E676B460380DF3D503CC7E30BE31E05CC9F0C401", - "ciphertext": "16241F92F0A0AB166A9B4B64DA10A686B9C78B989A894F", - "metadata_key_hmac": "B16BEB1B3CBB77AEB8F3748286FCEBD3F6F2C21EE8C201C5E57B9BE24E907318" - }, - { - "key_seed": "A845B8E174D742420B23349E36ECAF6E454D16F406F9BCA265071B3BD07662A5", - "ldt_key": "D8CC56D5C1C4CD27BAF1ADAF310A61E9E9934054D067E7D5EE8B4F2D91AD0540181981BCA0B356F49B38337D8CDA5A500007FED0AC21434A041F0E86BF36FB08", - "hmac_key": "8A78726DE42E0D88076AD5EA63DE08674CF8751BDFD0B9A74D233FD5511972F8", - "adv_salt": "5656", - "plaintext": "90D2B234C73C4DF113A4089EA4695FB3E1C5613A2C8F0DC7D0", - "ciphertext": "5053DBAB225D49C12C4FFBCD36711953A3E00B8ADBDCF0AF8F", - "metadata_key_hmac": "962782668CD846AC9D73E989A84F8FA095247B260ACB0E981854ACEBDAC13CF9" - }, - { - "key_seed": "959D5D206A50FC83E74679834926F1B4447FC27A28162C95CD000C9612C4E088", - "ldt_key": "3B04A47EA64743AC0ED199A5BA0CCA7611F93E5600BB51D799CBF54E25DFD95F893FBB7877660A5351A859FC0F75C6EA33B470640554A1E2DE4D4452747EAD5D", - "hmac_key": "74BD0A56417D845A30F13B84150705277DBB6971AE8E24B523B99E573711554C", - "adv_salt": "BF9F", - "plaintext": "AB0C6FADB67BD79EB6B94A0AC20567E926086E", - "ciphertext": "FF008FB69B2440F889185B21DE5C3392516A9C", - "metadata_key_hmac": "B268E72C523B1B0A969F4BB7474AE203EBC0E861643F1EC6B6090F670763321F" - }, - { - "key_seed": "51E94792E74002ACE7C3B512B18C37992BA25A9F74716BB981E322AD068348B7", - "ldt_key": "015E2B7B4F81E5EC77B382488E1B49E358562657A670CD3E532983F360583B2914E7B4E848051CA857657DD426AE9BD1C102AFAA5D4D08E7E48346E57E75E865", - "hmac_key": "C576F890E80E363AF243745856BC30CA6BB39FBE1A72749256C93AB7F87AB43E", - "adv_salt": "8885", - "plaintext": "331922A4837948608AEBEBCCDF8A44FAF93509B225CD", - "ciphertext": "C5B89D2504EE3160361D0AD031A1BE698DCC5C37BD04", - "metadata_key_hmac": "BA9060E2714880FB372713AFDA0DDC82C437C8B7E8BD37CD0504AF0B7D6B4AAB" - }, - { - "key_seed": "4F2400095D77803F8C2044BE940CC3AB2444B314DB20EAF0C1F837FDCD1B5441", - "ldt_key": "17AB4714F2D72CA4C5371768D7C5569F6111E76305863F3702FFB514ACA56DCEC3DF724C1C6544E050E89B23F5741BC9297CA834E99A1A44E221587FF77B2CFC", - "hmac_key": "1992486F199F19765F4CF13F1CE7EFAA085C116988B925F9AFFB89DAC36757DF", - "adv_salt": "5818", - "plaintext": "3EE4FC2AC25DD812DADCECF73A638085DB9FD791C20A40FD", - "ciphertext": "7FCCEF8CCDB9771DBB025A611269B1276B9C0CDDADF63133", - "metadata_key_hmac": "03B15393F8AD1DA3F2E7F58AC261017CBD3BDBB603545EC39FC44C887A003BD0" - }, - { - "key_seed": "E7137CC7DDA32EB0D1A6DCF6A8B48A14807D7F3265FECA890BE303333576FCCE", - "ldt_key": "5F090F80CC5AA508CF9A64EA25E2E84EFE8421B39D8946AEBC0D209BCECDAA3053A16E1EED1FF14213FC6BBF0187E75B0A1944DFAB7E793D4ACE94D418F42EE2", - "hmac_key": "45A6202083B74F0820356B21A83A4D61BF17E22EDC79274272332E6903E1A5B2", - "adv_salt": "1316", - "plaintext": "3187F589F42134ED6ADCA93D4412E1FC41E2FFF6", - "ciphertext": "97EEE19E9828D5FAAA213D0666B26873322A6F37", - "metadata_key_hmac": "36AFC08EF8950DACBC4049FBE005C001A773BA688CAB55AD71E3F05D4A8E1BB3" - }, - { - "key_seed": "BD762827B67F301BC4F1205800A102707E28899C983B462C959B59FDFBA61DE6", - "ldt_key": "0DCA2FD12F7F8240F9F401DF62FAB2C9653DA29817D747E6BE7896E107C08A946FBC3E606B73B5383B7ACE9817D7E3867E076AF7FB88F1FFF15C39E0AEA236B4", - "hmac_key": "5D4DC5B69019BF4D5DB619169979683AACC8C7BAC8D90704187B1367EA0D3B96", - "adv_salt": "0C42", - "plaintext": "4982BDCAA4A8410E4EC8114A87250768EED2DAC6666AED7B050A2875", - "ciphertext": "8238354F1F9C09F1F2A998FA4CF8183E601E8D1201DF4B7406C895F2", - "metadata_key_hmac": "2B4A242393CDB8EBC0096D1A821E902CCED72A4F091741B252CF307DBD27FBC3" - }, - { - "key_seed": "8A0747A091D9873604ED00DA5D28B4A671BC9F77A13275E0F57125EFE7F9EB0D", - "ldt_key": "F50A9C0F74B5E0D8A67CC9F401493DF30327AD605E0F978B822DEBDA52DF4FD2081641BE86B20D9EC0FC9A6551E1DFA8862EC04A685A86530346438F7D99CA22", - "hmac_key": "D12F236FA71A0E5454464BE860B6EF7FF5E73BBCDF4D7F3FF40EEB88635962F8", - "adv_salt": "3221", - "plaintext": "97CF5C94D322D5D5FFC04E1D598E163F60EB26C8", - "ciphertext": "40E8649F75C1FFA554406D5528E5935CA625CCC1", - "metadata_key_hmac": "B34E17DBB676F3700493F04649306EBAB8F3FBB4ED174B3D2208D59FEDE5C7F9" - }, - { - "key_seed": "5E75B1A297B2B785F45C13973332ADF3E739299CD692D9A30EFF819D6FD92A5E", - "ldt_key": "E3CF63B24F1BC910162625022E9D8E9E6652D66F4D8B56CE68A355E752A99BFF573EB0A4BDE1BE9D8C6CF1BE0F643A57BCFE4D749A0FBA6ADE3EB9ED7E63C80B", - "hmac_key": "70E61B022F48A8CE14DC6019A5BC6BE00DA34DD33FD7A927A18C67DCFFF59372", - "adv_salt": "19F3", - "plaintext": "62B9B3AAA7AE06C1CF4FC10DAB9592DF32D664EB1529", - "ciphertext": "690158B2A92DB0D89AF96B2BAA2BDA0CB815A823BBAF", - "metadata_key_hmac": "EE9F79CC56697C64835A45BB52F787F0EBF2F47F7D1F39C65656A0EDD942417F" - }, - { - "key_seed": "5F828B51F0DBBCF16F32B0D64EF0077E6E0ECF984FF6E5260ED08C2F199EEEC6", - "ldt_key": "774E5108F1F1E369B9205084718CB8482C1033D8C37CF01A0947C8894515498DBF9BB6931F1BCF3832BD3C89157B373E3D20ACA532907936A47E977A1506D695", - "hmac_key": "78A7578566907A579605F8C87EF2CD96B36EF30F29DFD1D19ADC6D080A7656C4", - "adv_salt": "BA3A", - "plaintext": "3DFA5DAE488331777806E37620BED8F6D7977D290D544A80A6", - "ciphertext": "EB54BE270C16BCE344F4007DCE950C7878EEBAFE9399FD2D41", - "metadata_key_hmac": "D70A299F865B49660C64E03E2B6A7D52FF6F5E0E334E2E5343150098136B59F4" - }, - { - "key_seed": "C13E52792E005B76773A7CAA506BB7521C7BB609C227D20566A0D34B401F5010", - "ldt_key": "84098CB4CEB398349234613AB71C4FAD607EE8E9889FB33393B6D6036EC4947D26BF1AABBE6C3798FA01918A6EF490E8405F6D00DEAB21CB1A74040FB37D6B5D", - "hmac_key": "E8091487A98ABF54E8A894597102F2DA954D2D450714000337CDD52D811C18EB", - "adv_salt": "7D6D", - "plaintext": "3BEDD94396C68C204AE757B0C9EA8F99DEBA24A089C8A3CEAD48B24363A9", - "ciphertext": "ABAC2A91A0FF82E1CF952777BDCE67CF1583D4306E302C25ABE0FE0DCC7C", - "metadata_key_hmac": "8758858A8DD887BE0B06A4CE5085FB489D7F8E523AAA2090E823983C400180B2" - }, - { - "key_seed": "99209F9ED8D3688E8A9BA71ACC974F6A33740EEE13D87E61117BBCD24ED46C9E", - "ldt_key": "2C8FA07E51065220E580BBECBAA8CED2ADF38AAD30483CB2AF6E93528AA00DA008B256EA8347C18974421E1D7817D8E1240E523221F223524ADEFC87F23BC245", - "hmac_key": "C2D44B7C9FBEE5AD19FAD4A2539B070CD52A5E4867843BFAF8AA20718F8C8532", - "adv_salt": "26F5", - "plaintext": "5F7788A29C92701BDD991C4F0BBBD89FE6D79830EBD58FB5DFA57F", - "ciphertext": "6966882738DDE48CC1A810C98F33177E41919B31D2E40780D94BB9", - "metadata_key_hmac": "B5231FEBA78D42FFF32386DFCBF05E4393B7883EC71D15774DEDE75D65063705" - }, - { - "key_seed": "966DF7A7630E058186C2F28FEA9E6B9D581DF8CDE8157EE6442FDCD09FF52242", - "ldt_key": "0D99B0EDA92AD23AD08913C243DE0E033C3B6D60E9D9D8DD670AA41A14A4D5137FACE3AFDEF44EAD7E42DD20AE2A0F56B4441280627F5949315D1A5D83A0361F", - "hmac_key": "80C2A8E33E4A6BBB28B97B2153F3C5781FB735DD082220AF5F83E21D076A5BB7", - "adv_salt": "9F8A", - "plaintext": "9AC43899EF5C19527C17A5B42490FEB1932DBF3D", - "ciphertext": "052AB261787C5C32B97FAEEF61F2F7300579EA3D", - "metadata_key_hmac": "E9E5C776B7933516400C1CBE21C865B0EBBA231A48B094741D6C05056E81604A" - }, - { - "key_seed": "3ACE45A27191E9008E66C3DB980CCB5044E1153E4DD3FECB051B26E568E895C3", - "ldt_key": "B3D4B3B28AB6A70AE36C589C5C16866FF9B414FEDF67669CFDD19FB085B64AEE16D6782B9E5DB2C40151BF21DB2DD322640200454EB7C2BF4A21FBE60A1C2C86", - "hmac_key": "146363C05656929CD63ACA8CE77879F6AF09CD6F820D5AC8D5E298283A3B3425", - "adv_salt": "FF1B", - "plaintext": "E44D6F311235103E94C01A3254A924794F80D0", - "ciphertext": "6561655D1D86932BCEF36373B893FF3BA770F8", - "metadata_key_hmac": "24DEE3BA49C15DD28B304F82F0A47DE1CFF96D303361E3C705AE931620ABCFF4" - }, - { - "key_seed": "1EF1E6BD839009CD1815ADAFA4C842A633D992A4714EAC96134D1C28EA6C402C", - "ldt_key": "EAC3A6D962F5F1165527E85503E1C94DBF60050239E7833701295AB0AC6FA6F6AA6002D87E2FF49C620E55E7A3A466BD71CB5138AA781417E3194EB2DDC4E50C", - "hmac_key": "D32C2E77C735D326B3DA3E7E719DDAA155A1273E07DDA985AD15922D5BF65CE5", - "adv_salt": "A239", - "plaintext": "D0A2F69C1C0B59F54EA0B5F87079235890E62E93B72D71", - "ciphertext": "9216740B6A94FD6E2C2777F1E4F182491D6E662DCBF0D1", - "metadata_key_hmac": "9A63CB63EE1C702468D288341B77367DD59EC18F6711038A825C33553C4F7D8B" - }, - { - "key_seed": "8B2535AB74D0E93B8E364F26280FEF24B6E78F93110F5BBF533874073138BC3A", - "ldt_key": "35BEEB94D853346D0044288FEDE4BB649BF03356997BBA1FB994C29311733BE112474086B34A429E6D56D5C39D429DD7A8829C3FB8E5DE99AA8805CABCE2F68A", - "hmac_key": "7F4E1608A595E7DCD915EE1339679AF08290A663ED76142B564CF33AA60E422B", - "adv_salt": "8D71", - "plaintext": "8B7C7D68516FECA71915B44644854032", - "ciphertext": "BCFD8E27F1A7CDEAB05B41FE8E94E813", - "metadata_key_hmac": "D1EC3ED33EF17B53D2E5C712C750AB9792608025A79166C87A631B5189CEFDE4" - }, - { - "key_seed": "68B0C0AEBB1B4F1A8A398533657B26D224DF5633DACC640005FEFDDB30AA85FE", - "ldt_key": "E3CE400AC3AD9A993FC5C938CF1444CA907C0E62D3E399B40010E8FF70D812E2F5D0BF2F77796445C56CB25797B39359A991666217C8B3615A62A69EE56E57F2", - "hmac_key": "EE969BA6D7F13BB60136DA7450DFD7C03E664E39AD3F0FCA38E382D46C2BC5AC", - "adv_salt": "4BC7", - "plaintext": "607E9F8FD75E15BE4FCB847A15710379EF38E4B31BAF2C7C9A615A61B1", - "ciphertext": "CF992537BD9F2485F7A8AD17BC86EB95C0FAFED4E1F809C67E49BE2354", - "metadata_key_hmac": "25C04A466CE86994FAFBA8AABCF18C35E67C314396ABACEBF5EA046E551E814B" - }, - { - "key_seed": "9A3A9BDD903C0173E410A0A3D14A8B91FD6FB25618D1D563CC029FD13ABA88BC", - "ldt_key": "F0235A77EF2E0931E460CEE605F87A75E9A94D62D0E7D37CAF0523CEC6D13C311B1F9CA8BA4DC2EEF40B57BDB36DB2EF718CF8F3B48186A01517D3CD766A7101", - "hmac_key": "6B112539523DD69EFEEA53DC54D0821B84A1BD2B37AF762728A82BFCFCA19949", - "adv_salt": "3EF7", - "plaintext": "C3D22D4D9B701A1459C3E76AFC5C8017", - "ciphertext": "904D9A291CC4CF4A4BCCC38D387B8205", - "metadata_key_hmac": "D8FFBFF6FF7D4E7D1C3CD8F77D4E2DD517BDCD57629394AAFBC19C7F0CA7D485" - }, - { - "key_seed": "61E8511E69651AE7A73DBD04B941FDE17A1C52A3F2AB122DA320E974232E6E95", - "ldt_key": "6B7BE769068F80C0A373EB0D42CDC1954F74DE30A1CEF8E26D4F41C077AA068DE2F6AD43D0FDC3C7065D5C5FE0C88423DB13FD07D02FD2E5125EDDF85CAD30D6", - "hmac_key": "89C68164AF8C1951C587F92EC69D306A6FC98BCEAEE158F1744887309E2B225C", - "adv_salt": "D6C1", - "plaintext": "93F8A03B2E25AFA0845646761EFEF765589492", - "ciphertext": "39F3003C41BDE3078B7DC178756596F2FD9CE3", - "metadata_key_hmac": "91E93B8A40ED64BE00109BC8A7FA7BA556CED575F4FED68490703415B515C59C" - }, - { - "key_seed": "F50FBA7C9FA978FDFC531AC8D80EAC2FCFE60597C3888E2D9DE78D743F44126D", - "ldt_key": "45ECFAD30CA47A46F9C0A943F90255B33F96ED1B1443B47E5CA93A7787FB7E547E435A1885AC56C6DD9E19F2496C6158AC8D3E85A5D66EF5E91DCF6EBBD05577", - "hmac_key": "D675D76E2070B2E5DF63878643CFDB9FEE5F1757CDEBB713B9A888AA808834C4", - "adv_salt": "BE73", - "plaintext": "9DD7CF9D31109D0319EFF2B0B77BA470A4", - "ciphertext": "AC2387B613EE0C5E2F1C726D1E2CE80165", - "metadata_key_hmac": "7E8E81B28F287F68DB90EC58BB234439EDE6EB16076BA17E6C9A9089148A7A12" - }, - { - "key_seed": "0E3AA4661227ECF85B9803754BFC759904E1146FB14805B2C466924184299853", - "ldt_key": "B347FD5FDEB8592B629795B73376B4FDC5DA39330217B4D6763A700EFF120BA7B81CCC2B212C15F978BBCF3CD52CDAB68CE9334ED59F9FB976E5B549E38AE162", - "hmac_key": "BFDD346C88E410A7CE622A9BBD76EA1E17D8C0B2ABF99435AAB124CC52D5B456", - "adv_salt": "FB80", - "plaintext": "73FD04EE2340B9B90BB39A4533A8EAC1D6E79498E32FF240F657", - "ciphertext": "09FB6F7D88711FBAEEAA9BE40AB489976C0F8ABC0676F7F7CCE0", - "metadata_key_hmac": "4C8CB886B3A608257349BD50B51497ABB8FAF3F1343046991E283321939DCBF5" - }, - { - "key_seed": "C099343FD4A232B819F963BF52B5F1C8EB6A31389EF5E3D9E9136E13E4C45C05", - "ldt_key": "88DB810F77BD9EDD223DFFFA1C030A222E4C876FCE7535E2F9F34087CA64BD0CD13A336FD968044C031234BC75837F5AE1CDCE777D1477DD063178911DCD30AF", - "hmac_key": "D95134F685C48D23509BD58D8117FAA6A91640F4E08DB3CC45DB252FADA86B43", - "adv_salt": "B312", - "plaintext": "DD081FCCB8A5D4CF75822E2C5DAA2DC18E1F03AC881097223C", - "ciphertext": "D7FDADA1C6F1308097BFC739AB1506EF5EB0BB5DFB7340EA1A", - "metadata_key_hmac": "112865C8F64E18D6EAE178D59A83FD2C932D8D0B6DBBD0442A19BA01E85E5286" - }, - { - "key_seed": "8CE0F66327998E3F4C4DC7A9D2AFD4C96F8348716071E88C6CAE4E145FD9868F", - "ldt_key": "474AAC78E2EF5A8256B5AF15131DAFC3186C8BF80A26A092924569834745B35E50EDC31BDA3AEDBC73474312FF65E6846A02C848C01277BE6BED34FB8AF255AE", - "hmac_key": "C063797BA13AA07E77EDD2ED6AC7CC95B09CD318F2F57853DF9F621F5DA64D91", - "adv_salt": "3886", - "plaintext": "F438E75C0B6EC928A2D6446250613E3C", - "ciphertext": "45110B3BAD0E10347F5507AD69C4CB0D", - "metadata_key_hmac": "6919301B93BEA50AC96EBA3B14C93E995EB935B422AEF3572812D95139A20CB5" - }, - { - "key_seed": "BE71C52BC69AC9B79811B15BC2415C637E6A071A4A0DD2B8C3B61450960E3AE9", - "ldt_key": "2EAFE088BD5C2CE73A7D441DF39CC7B75A8F8F9249368087647465DB4587F4A53841B7C22852723D8523AA61A890CC75C2E546BD579D4AE15C22061D35942A9D", - "hmac_key": "5D515675C2E137AFBEC0814EECBA2C96DB4233AA0590C77EED7016978A6BF4A6", - "adv_salt": "8B45", - "plaintext": "43F7EDE6E21FF7A7389F0071A5ADD10D18ED3AD5", - "ciphertext": "4AA9A385D2A9D46086B02411DB0B6CF0CF38F1E6", - "metadata_key_hmac": "DB6E1A1D2B326E3761639FFC2D7CFE7D14340155EB93FE921DAF1742CDC8DF42" - }, - { - "key_seed": "F4FE69415D899F4C4BC785DA4EE1A7CA27A54623CF2F6E43D63354BE663CE05B", - "ldt_key": "2BE6FA71806DF6EA92CA2ACB1DFC561732F88F80C429132B9E803CDD8EC1B3677D3A86DF6B4637A56C1E340D6A40B8977ABB4072600D73B76F8795299F5A848E", - "hmac_key": "3AC4D4CC8A6D1E845E9566203E4448EFD72E4F5628CC7759E64071D47098295F", - "adv_salt": "7CCC", - "plaintext": "5348BB05E07CDFA4DE1A5032DC77AA18F8176B50D573D42A46E187349ED1", - "ciphertext": "9403D67D0A27A1409CE20F9F8B7D54EA92705E69379370C71A4CF8EF02E9", - "metadata_key_hmac": "0591E04F26AEF6FFC35FD1CBE405095B09D836A276A8F9E5DFD08820AAE41D4A" - }, - { - "key_seed": "6A408471C5B4AA6A83C759E733EC913838A8AB51DF41F6E5BBC6C52103996EAB", - "ldt_key": "BE92E7B3230524E7D73E1641D7C17CDAB6183DF53BA9E23F2C06D27E0766D634C59D03E8352DDFFC3AC02FEFD1922525FC93A27005181F2B702275C6E5F58686", - "hmac_key": "B30A4502CEFAD6C91BDB8AF890188223FB9BF632239F4F8543EBAB2F5D44893B", - "adv_salt": "B569", - "plaintext": "D301E83E71779D5A5EE57D2DD388F8902E40B7D42B7D005A73", - "ciphertext": "73C7DA92FC745D6AF5366AF3C4629FE9CBB83A07148D049AB8", - "metadata_key_hmac": "D5729AAD46358847132C4CB9BD09086ED6660098FB562ED5096E148FB197CF0A" - }, - { - "key_seed": "A7EB4F2F0675BB6B5EAECA9F62AF19858B8176B6C65DFF1AE6A079BA62D820F4", - "ldt_key": "37FC03570EE05E7382EAE553AA4DDC83A9CD52E9838788D3F1A7F0E31E0F48B0AE60B5267331C1AA70560F5235034939264F77F1C2DCCFD7E5D8B21437230582", - "hmac_key": "A0D12D31A7C92885F5EEEC124877D267488C54666A7483695C738FE15A0054E7", - "adv_salt": "7146", - "plaintext": "ED858374B2F63FE2295C03057FA1C608", - "ciphertext": "DF2BDD32B531487175FD70B52EE04359", - "metadata_key_hmac": "29E61C005E33B275034DF4D632CC745F589B41A57EA1DB3A932A3BA3763582E5" - }, - { - "key_seed": "18EFCDFCA16E365030A5262183C26DA73D04E7AB89174A49FB4362C66890E118", - "ldt_key": "5148EC122339DED20615FB7DA30BF8BA2393CDDF53BFEB2BDFEDD013EC712644DC7C66A4EA0790088F589896900A3E4DF303E9F0BA07ABCC6005972A76EA7014", - "hmac_key": "61954A3DA2BDC3F3BE2575E19A57795F5815BE95F7EBE0CEC73E61090A9B1F1D", - "adv_salt": "5810", - "plaintext": "00EC894C423C147AC4D010DEC2E9736D44", - "ciphertext": "E9BE57C4FC0A029AB7B00D059E2B85F19E", - "metadata_key_hmac": "DB51ECB68F815EDAC9E9224B092829809BCA51682683A6CA4DDDCD8794018726" - }, - { - "key_seed": "25AA14B16817BDBCED1E9694EBCA2F8BAE8FB017E55581DDBEEC6F0F68FF0F8E", - "ldt_key": "D326C60BC14193B314C09549AFBCE6C16783B28DC53561480EA5377DB3F1F4A71BCE8D000C9366E4646D1BC463EBC994753CAC00C4D99886DC4C3DA81B9D09BB", - "hmac_key": "4D3473A979B94BCE625FB3B6C0EADB1BAB813D7EDCE8CDF7B008CECFB5E26B25", - "adv_salt": "E239", - "plaintext": "97012D42AC4EC974B4B3BEFF19822A7CA44F26690F68409FEB0BA7", - "ciphertext": "2119590810AC61AA22DAC6A2472331DEF9910F169AE9F578449693", - "metadata_key_hmac": "CF8A02C467D95938D541EAA0FB11D88D8337B907DBDEC83C3E3B43252232F74B" - }, - { - "key_seed": "82B6E5E0CE0A08A2E3AFFFE760C8A1D2EC885993248390D4F5E93B9A04F4D758", - "ldt_key": "A7E418C2C993648C90E6FACF91636DD34EA7D6BEEBCFA22C116B26AF2D5C2CD900B277B85A3E731096DF9A8A33CFA783FFA3A14EABAFAD6C1D117AB608A27DF0", - "hmac_key": "9D8F7FEA188248A5104B1DF4F79A9F6A5DD96ADE0DC893F28FD5570E4AE28438", - "adv_salt": "7CF9", - "plaintext": "9BBD2A7D75DFF4C34DC90AAED6814466D9BEA5", - "ciphertext": "5064BE5632989938326F75233EF85485C1AF71", - "metadata_key_hmac": "85FC88E620E660A1F0BC705A7A72F04F908494EDE585C7890BFCB6E0074D4655" - }, - { - "key_seed": "4311E1E839B5C8ABB86378C3CD11861D230BBC9E6367184EE02A74B9BA73D0D6", - "ldt_key": "B5AD803ADAC55B93943AFA73E9500D6CEFD2F3FB75CF4B532452C68E2A9C9CE4497E260A0F5991A058D7154A954BECC4E1B227240EDD9AE661C40734AC5E5289", - "hmac_key": "444C68A622F716A29D1B042BDC2848449635C6557BB194CB04D4EBE9BFE3A538", - "adv_salt": "5182", - "plaintext": "74456B98E2FEAD8E389B4D4F032CB7A81664666C05C763864E523D", - "ciphertext": "A5B41A2E1668084498477567EC9BE1756B32AD19E2AAEE2D7B0CC9", - "metadata_key_hmac": "C5A709EE6A1294E887C68C4DBBB6E77BC7977C96667694BA404DA79B2B0D5BFB" - }, - { - "key_seed": "2A13635460A9710B09F643F2CD2C220B5CDD9F98F4953CB600997A0058E8A556", - "ldt_key": "7E9D0633EA841E57B76DE4B61717FF2B31EF5980F1E02C52B0A41584AD47CAFE4F8470157DDF8314AC1471FEA14F4FB51A76B6D61A89AFA98C7BB8B8EEC0C92B", - "hmac_key": "3802765D17628C24C6223D0E8DF9AD55D3B277DE4F85708B6E96F29319B0D718", - "adv_salt": "6998", - "plaintext": "F7D8B1AF30844708D179106D5E329C02D72A7CD6", - "ciphertext": "5AF1C2E04FBAD114E66BDAD7530398F572559757", - "metadata_key_hmac": "430A3A52FAF79431C1A891AA9C3D705B17626B829EBCA6F7AC095CA938D08400" - }, - { - "key_seed": "C2D25F59658A7206D3D749A794B681D12E6E0312DC1B45A8877A47BCD4790EE0", - "ldt_key": "E62E721FB8BE56F5ADB52434D778EBEF25CAFF0E184D448548CF3DD5372ECD4F7B8F8157CAFDC71AB78BAC3A236BD4A36F7D55ABA6E3091B3FD5CB56D4F9E5AC", - "hmac_key": "61B26D9D3FC8D6216ADECA830C1413590194FA25FEBBC84AF095BC314332E65F", - "adv_salt": "36D4", - "plaintext": "5D6BCADF581061C5CBBF0E6A40F17DBDADE5A7C7BBC1E8A1", - "ciphertext": "5ABFAB0B064982F46175541B4265D8993E1DCA74120B3634", - "metadata_key_hmac": "0EEAEBDF097DE3D854D3B0AAFD26DE8C2F0D96244C27559BBD6AD3E4F2706E7D" - }, - { - "key_seed": "D846015F3A085AFCB52243AF98B86D5FBC9FE00B018F89094F2598436136DA10", - "ldt_key": "8C6B74CB4BF62487EA664B1CC00BE98A2077A0C6FD40A0042EA01695043C73CC3EE81D6E173977D2BE66AA9CC8236F299141B0329335ED5FA2DB77CD1FE44215", - "hmac_key": "B96764DD552A8A498A71ABA08B2016C6A476F76D5973BF8BD726BEB0BB8DD765", - "adv_salt": "C9A4", - "plaintext": "D4447137F58623746148C336D14E67BD3F29CD7C2D1274E0", - "ciphertext": "157292352629229CE134A70B8BD146C252EB926C4107AE2C", - "metadata_key_hmac": "BA859EC74F1438FB9FF40FE44DB76ADB052B81E65610E327570463AB751DB0B9" - }, - { - "key_seed": "73FDD0C8E8FE44D996FA9180979591EA2448801AF4A355590F2BB563044E968D", - "ldt_key": "DFF7BD9BCE632499BECE737F13E127580E93233151360A07981C7E6226CDF2061A4CC2DE0FD7FFB770E3CDCEE6888C23523088DE0E257C37E01D24ADE12EC869", - "hmac_key": "6B997391B1DAFA341868A6F6F69F88A759839BD46074CC36D84A855E7EE761AA", - "adv_salt": "C576", - "plaintext": "6728C48ECC39EB80D2919A307C96C1ED4F1F760D20C75F690FA2C0687282", - "ciphertext": "9FCE1D5340D44AB1FDC5915B9DF3BF6362F24A6544B3F8A1A7D4250CE751", - "metadata_key_hmac": "0FFF129F5B044196E5188692B687CA74501D7D07FF649AD73B95DA3C22C36FD7" - }, - { - "key_seed": "6DFD6D92352D2B434AE3AE589CC7AFEB88E35F76B95116805DE340CD6E456083", - "ldt_key": "A448803AFCBBC98631397AECCCF9F16723CE9EF37A9E94920260A15332B722329DEB61EBC8CB7ACF76D4AFF0A6DF60C159FC179E32B4FCA9A9237987699652C7", - "hmac_key": "BEACF74249CB4AAC9A74FC2E817D8FF046B9279CD7D51D0816EAA9A2680022D0", - "adv_salt": "A4A0", - "plaintext": "24C60DBD7A43C2B9C7A5A4F17991FAEE", - "ciphertext": "8EC524A39825365B8649D164FBDAFB9B", - "metadata_key_hmac": "C28849E4E7C18B1E42279AFEBC21866DC63B5C6EF1041568029AF4946950F208" - }, - { - "key_seed": "5B556655C181D91F2571D072841B954622958A26E8B5FA22329BAF285EEC95AB", - "ldt_key": "88367E8701FB603E6ED5BE0D1F6DE4C1AEE0E79C9196B52F8E84B9DD8D60C16F7724952762C6DC2893F8287DFEF80A55C49FB417D2CF65B2CDE617ECE0062877", - "hmac_key": "0D686156F80AE8C1AA30706CD0ACA0CC860609ADD16948470CD4975774F55C96", - "adv_salt": "E675", - "plaintext": "712B448A4315C640379DE064133DE0E1", - "ciphertext": "9E6DBA6F506F10E84ABA9D777D005919", - "metadata_key_hmac": "E179FF8EC43888E59573387977A22EB28B5DB9BD1ABBE132836E63E66DD0EE7D" - }, - { - "key_seed": "7569FCAD04512A9022654D0C42FC09E5EB23EE8CCB2BCF015752DC23258DF74C", - "ldt_key": "1EC058B5ADED8CAD6FE9E7C519CFAC976E464B6F1B2053457B60F0EDF67E9A69F0A3FFE26F9D9F1DB5F9E90CB5C44F765FD80E4B0D84EF0D20C3DC1CAA148B57", - "hmac_key": "4C0B183A19276F6CDD389EF363E7B73D26F52EB72E360817458F8A355B6A52B1", - "adv_salt": "ED54", - "plaintext": "3F66104FD3E653B05F7CB8C436FDDE2830E743422C9FE2", - "ciphertext": "882EBD21E8AE0B65901B274B564F6F7EB27530735CD991", - "metadata_key_hmac": "95E2D4BAA5D346CE447BF0CAE77B3136D6EDFF7B73720B8174CC7FA6AB25C60E" - }, - { - "key_seed": "D734E43327907951231721D8EACF1CE1C67CF8344DCA240625044D41609B66CE", - "ldt_key": "A2500D3D317A4D1FB41D65DEC6D308925D093E0FD1AE16704F85B53467265681AC76581CA18EDA7083C79EE61ABCFEF9C1E0E40D8A676C6A122D91C9691A00D8", - "hmac_key": "10426F35CD6F93E45EDBF4B1AC284B0245F79126F7F713B82D8903C869989C26", - "adv_salt": "A66B", - "plaintext": "375C7E3373E88B579D4A4D87E5B8ADF9657180BBD647", - "ciphertext": "1F88538743A5DD988CEA35EB1B60DA18D9A0DA08EAE3", - "metadata_key_hmac": "C9B24D070C4E1D9F916E514D8E16CFBD749C2E788157E35B622D437B91423BEB" - }, - { - "key_seed": "75BA47FB5A778384C5C92159BE3D12E13DAB1466FDD200A2FAD9EE3E624392D8", - "ldt_key": "12A62E7C37C689305D617E243172FC5F608B811B0F07C5616264BFF94715C193956D1D714D2E7D10A437B9F3B412F50E2C735B3481A4D857B39C7CD090277DFC", - "hmac_key": "F1ADEB123E02F76FB0AE9CE759D0FB6D23931A806B9FBA3159F1BF0B5AC41DFC", - "adv_salt": "3BD1", - "plaintext": "1C26BCC5456D118D9DE9C0FEB5EEDA73F3BA16CD0914F9", - "ciphertext": "B819FF5268145E99A8EECB759C776C426BCE55163047AD", - "metadata_key_hmac": "CB31D51393D442A6A13518E02CFCE0F0301E8AFA44FC60B853057907F116CE68" - }, - { - "key_seed": "AABD54056C692FEA551A7199FC978C374D3CB32527CAA8920AA839B6F6670C34", - "ldt_key": "A84809E217F9E1AAB6A3C11B0DF47AC0F7A15E8D4218A842299180EDF56FFBD1E71846C83622F7014B6DD3EC1B1C3974D632F3069C88E477A124180BE903BF07", - "hmac_key": "F1A83D7FA59840297D52B05C679D66E40657402B0C501F0B8F139B4385F392D2", - "adv_salt": "8E00", - "plaintext": "06C795A1252A9BC6B8C71DAC3D856256F15BE1068AEA86E7BC68", - "ciphertext": "0634B91779A563C03D70EAA14E0B0C7E6A72A32D5AA3F9D27D85", - "metadata_key_hmac": "ED6417BF208F7810B9C4C7C504354EFD629A00E86B7CFA2EAD5B2103249C90D9" - }, - { - "key_seed": "28778BF659017AC84B559C88882D9B309AD2C92C4CCBF2F8E512638D66C91733", - "ldt_key": "5CF94149484918D409F3E6E0235883118044976F2D9379C09AB55A875676EC6A9C80940DD890FF94407DE477EFF0F1F0A7D22BBC01592FA6AAA07188C02270A1", - "hmac_key": "4F207486F2A8504F64705AED1B1D197A26F26F284F0E3A8DE44326F16968562C", - "adv_salt": "E311", - "plaintext": "32B3AF5757B29A5DD9802E6C2CDBC5BCFAB6E083F0FC87A4AD62CE85BFF655", - "ciphertext": "7A4E0A1435A24A98005254F2C9AF92D3DEE98F8CE1B97C2508C1C0E3957E63", - "metadata_key_hmac": "2ADC12BBE2A3C72722721D8C5B43A351CF2CDD24BEBD3FEF1FA186A9A96BF11F" - }, - { - "key_seed": "50A99CBB1FBB19263E42AC51D667C1C0B7ED680B43C147F0BAD56279722733BA", - "ldt_key": "2AFE26490D490840CFE7332BB070E05BEC9D93981469769C2FF03F695180D828A9B7273F4B541DD329E7E9907A91571EBBB832AEE61D2A7FCACDDA689C7D24D0", - "hmac_key": "6C2AA4D3940A672CE7ED32E0B0C67D7BCAADAFF90643618482270C86B2789ED8", - "adv_salt": "5FAC", - "plaintext": "DE38D1F851723F02BB74C7FF5FF813AC2DAF7880C08D0188F300", - "ciphertext": "1844A6EE5F4457EEC3906B9430752853EE032577C425119F611C", - "metadata_key_hmac": "522B09A18E7168063FCD85D0CBBB46E49B199D32FF1B853D9F5A2876D28EA24E" - }, - { - "key_seed": "9FC111AB46387C47EC77ECAD602AE550A411D4C433763D2FFDE06765728C86A9", - "ldt_key": "3F05DC0D3297958CA2F3441821C02E48013C92059D85E43FD239B806086D73C81EAE6C02050169D47FDE796456A0F02EB595672C9A740091BC7705395D509B3F", - "hmac_key": "F631CDB66C21398092FCE374365D385509B6F89C7AC5754AD931E622F8DC6B0F", - "adv_salt": "1A27", - "plaintext": "839A7F8CE22B6796D4AB453254A7E06DE4004A9F7F41FE", - "ciphertext": "4EA1991ECCE09408C1F3E818B47965062AA73D2B105F86", - "metadata_key_hmac": "4804DF0393C3AF50066C999B7593E9BD09C55F5D5363DA3ECBDE091A9A5020C6" - }, - { - "key_seed": "9085A08B9A529F4700953F9214136706C3AB56B09757DB19A733F646BFA689BF", - "ldt_key": "4261798242A6419B04C3C8580D45BCCC14E955085F1AE04A528FD085725C1EA92786A33C2FE0361665EAD307F606B1DF250C879171518EF33E3876A37F694A0F", - "hmac_key": "5C5D9187A1291CA90EB9EBA77F1AF3288FA1980332D874529AC94814B2E6095B", - "adv_salt": "BD05", - "plaintext": "5F1A621C4CFC22E0E4D622DAAA70E5178B", - "ciphertext": "24EEDF908E842903668F2501CCE5B1C588", - "metadata_key_hmac": "3769A0AC03460BA4A4D99F354ED894A292994B469BD225B91E852805227BB60B" - }, - { - "key_seed": "BE2D76792684F3AE542005CC584DEF72794882A9F239E8907F9C4D077A75753C", - "ldt_key": "D2D7C518BC1295F1D0D11D19DAFD49220498F8942251CA0EC735710C3A4FB706B34EEDFFAA10E74686E1C2705BF5320645349AFCEC4391AC9F064A6ADDFC662F", - "hmac_key": "CE7988AFB852B691E917B6B40DFB760AFFCB5E27B6C547F3B124A0328BD2BB33", - "adv_salt": "F712", - "plaintext": "5CF5B0B548AF0BC3331C4425025ECEFB910858B3BDF0AE86618AD11B72B8", - "ciphertext": "CDB48FADA18E4F7E0025B62F3D052529EB4CEF8E5C0996A7C5CB9D3EBE9A", - "metadata_key_hmac": "6C675B3B1471235F10B93BF06919328EE45F91CEE0FCD5262B08DE13FC1E0C7A" - }, - { - "key_seed": "A71EC15A86B5503D5B378EA02B12311B3E3666745687941782FF0E449DF555EA", - "ldt_key": "52C143EE553514DE2237F3D32B571AFF36558EE58640BE1DDDE6C94BDEA34C59A694D2EB0E0839852AC2BE1FBDF288603178E0A18FAD133115E2CA7E6608EF2C", - "hmac_key": "2E503289FEFD8B4E8B5E93ABBE92A031869D7D8914238AA7A31151486E5BC091", - "adv_salt": "5A5B", - "plaintext": "4F433B75A1FA22425FEFE0FD7AC8E402FA1431E7612EDC99347851", - "ciphertext": "11B6FACB1B39677CB8C372AB9357043773FD32795FF08B4B3E3323", - "metadata_key_hmac": "29D4D89A053A7857630AAF59E23121429E5F47F1269E6B83FC448AD00CBDCA1F" - }, - { - "key_seed": "F05EC969A52DB799EBC2A857313FE6176B7F2D555594F2BB4BAFCC19040C7AD7", - "ldt_key": "FF591DC26B212260EBD43D17D08D6702732F5EC1E15A420EEA406EA2BF26D7BA1460F9836D0BA5043BA2B45AC62CDBF279B99BEF728FEA14F0407BA453EE12F1", - "hmac_key": "9894B05916662C8EB0DA8ED3CFBEF4C142302D38DBCFF6B0137714398682D635", - "adv_salt": "7DCB", - "plaintext": "F001995BD1175042055FB5E9F65CA877065D70538B3C1A1C0466", - "ciphertext": "C76A2812EDEB6FE15A71A87C1E774CD7D1DD8F0246ED5E95952A", - "metadata_key_hmac": "7165BE02DA03AF773DADEB1107070A1E66F96426AB17624A6E535EE991D6BA97" - }, - { - "key_seed": "332FA48738B516DC5C7DE58C4922E7AB27912E44EAD434A3D758A57936606A9E", - "ldt_key": "1F79FE122B4E585A898B53172EF5D29DAD6EEBFF7B620A43B79108083CADBA5E1F347D044CB87420003E5CCA8E9B7F2C5BD8FC91AF63924DEC6445A135BA346C", - "hmac_key": "E4AC9347677DB2BBF6730D4FD7401A919E2356B5B130F0099648220F7D170280", - "adv_salt": "E54C", - "plaintext": "B66C2F1C04892188D338090EBB3B79B10184F8AF36785EF1BCE870E07A", - "ciphertext": "8A12EADE61D558CAFE09354AC08484C3BB2309294203F009AE552E0750", - "metadata_key_hmac": "F097551D91430B3FEDCE67D1B95A466D04AB1C361F8ACA47676387396C69EFAE" - }, - { - "key_seed": "83E1C95BBB9D0F2F5FF04C04135C44C74F7FBBDF0A3E954B083D28895636F570", - "ldt_key": "406B4A3B05C30F607342077EDD7C0B1AB5A96861F38EFA221A804F691EDF82272AE1850C223890C1E2CA3624974ECA2EF0EEAFE92153D6B2A76FE8A50499F3B6", - "hmac_key": "9AF63F1E511117BCABC058DEB685486958AEF0DC19C8627F5CD004FFF3EC0297", - "adv_salt": "1B1F", - "plaintext": "BF1144EF14BF286F6EBD79A890CD19EA560D12E0BC3A33", - "ciphertext": "2BC58BAC575A72346D9198498EE020FAE15FF232AC5C8C", - "metadata_key_hmac": "E6D8AE6D060801CFA0A7DE1953C82415F712BC3623813FDD79EA8ECE27441967" - }, - { - "key_seed": "B16EEE688EF2E975226581946F2474FE9471566E9D7BC198A4E1E59D9E924ADA", - "ldt_key": "AE056783CE871C8F87BE39C0BAB58DA475E64232336B36FB7EE0CC722A50B015D377F75A5EA28D05E8DBD6A30D6D159C8BAB40DB8BBA2C7B65AB3CE032083C2B", - "hmac_key": "F8CCA6345A63A86B3C98608B3F81CB87A0101C6D6472C8A233C33B14477E01FF", - "adv_salt": "2277", - "plaintext": "14D8647A5B948EF857869BBFC7C2A4386433", - "ciphertext": "BBF95D28B4F8E944E60618FCF36EEF7987F3", - "metadata_key_hmac": "D50F850029616818304DE732CF9C0F9E0C2E1B38052575B3CF3EDAB4E09F047F" - }, - { - "key_seed": "889A1CD66AF641EF76A24C80DF360BCD030B39AC12E4795DEFF88D9310937232", - "ldt_key": "56C0941AF6C85BA3F6B4F2B66AEEC0E166B2EB1FB0DFD97F3032C9282145D311C44BFE289D114628E0AE0944A6FAD1DC6E6078B66659BF02E2053592731CF2AC", - "hmac_key": "A7CD55C44A009CE9083525BFE3A2D5A183A772004BDAC2B7D41466AF1B71C020", - "adv_salt": "35A5", - "plaintext": "1101FFFFD2839177C6D1A49B34128840E506", - "ciphertext": "B379D7F3AA98D8B4613E961EC0C6EC435316", - "metadata_key_hmac": "8E04E11B52FF3FF2273C615F4B1E4D8E195D19B35FD616AA38E009865021CB06" - }, - { - "key_seed": "ECF470CD37ED8B48640531F3E7D4AEB728B6CBD8C9C0B7D2510C63D93FF0A091", - "ldt_key": "4263F97589C7A435494E2A9F40E6F2B47B9FEBFBAD5C2A807AF56D52F88AE2487BF354179FE0DB947359D3B94EB7C251EE678BCA19F8B489693732A9915D9AA6", - "hmac_key": "028C9C0A2EA89C0ECB9A9B96C4F1F9BA65EEA131054725E0CC5DDCAF203CA0D6", - "adv_salt": "61D8", - "plaintext": "DA4D5B503C04C69497E080CA76CBAD43A3", - "ciphertext": "DE3610A2D12F3C5C41A1525E09D74EC357", - "metadata_key_hmac": "A5BE078DA1268DA2192FA4463E3C954A97A85CE1537CB223C7FA594E74A4F0C9" - }, - { - "key_seed": "86E881B42649FE24CE05235C224632BABE8E1405A24C0DC28D24FF0AF7B60B68", - "ldt_key": "43299E37E6E8BAAFF036AFD9D368E9B1F5CAA1424C22C7ACCC395C1F6645D31E5433E86EA21CA62CC115A2857AE12C01AA26F697845ED26FB484362E283E53E4", - "hmac_key": "74D53B450E5844276EB6B1B54E3F39BCDC025F37DE4CFEC297704CFC5163DA40", - "adv_salt": "16DB", - "plaintext": "757B10011CA10BA4A407A7FB9C1F5E7BBD51", - "ciphertext": "E2056AE97E26E7FFBC8F331EAA84B35F19FB", - "metadata_key_hmac": "B8EE570FFF1449B35F26B19A4F2AB43CC26AAE4CFF79BC3170CDCC45213FADB3" - }, - { - "key_seed": "EE5337E8A310C7C94F216740C691A688FE8FF90CE183DAA33D7F042F4B50A1E9", - "ldt_key": "F9A70A0B325C72700845305DA134E227959BF8F0521AEE38DDED4EBB93CCBC09F6C2113A5EA658480FCB52742BA7FBF104D0A93A0548ADB4313A7EE2E6814F4F", - "hmac_key": "590CA973F27E2399B39D3E30B1ABCAE233C02B49D8E35EA708B322C34703C44A", - "adv_salt": "CC80", - "plaintext": "2C37AFABCD0FED7118EEC7DA89411F97261F4D2C84F8", - "ciphertext": "D7BF38B9D878A4FBE06EF3DBA6B9F2FE0CE830366ADF", - "metadata_key_hmac": "D9522B40F11053E5C57960A0D212C6A126B3AD67C5E12CB2DC85A5D120659E64" - }, - { - "key_seed": "4526C12D8ABF2B204754265B932ED65C1C272217F72F832D7ABEA54C31A0925A", - "ldt_key": "76304EEE88BE11C0FCDC103F80E3079B25C7F0FDCB97520DACDE9E0E65C6F1A0C3A0A9DEBD4BD0EEBAC4D65F7E9EB1B5F13FBA910679FA424AFA95B5CF9739A0", - "hmac_key": "71E41C3296E3C397C3150CB29C36875D4714C3321FCDED6E001D9EC65ACC9C78", - "adv_salt": "D2C6", - "plaintext": "B655F13794C279D54FC64D87C9594D7811D2841DF9A62D5A", - "ciphertext": "57783E5836E0811E618A405063779BA35A909A1E50A0507C", - "metadata_key_hmac": "22BE5456B855489256715A0931A5D686F5B87C6C9A0992E6A694EE3BE8FEF746" - }, - { - "key_seed": "461E80DCDA74BEDA35ACE9376E1EB05AA554771B9E5959EAB959E49A0E559300", - "ldt_key": "7574CA69BED05806C13F6901A5BBFA80AB3CC00DBA0B934DA7CE94064D7B55952941E3E81FC1EE7C61EAF1B30BE2141AAC6C7FFE8D0C33E1114A84FCF15EEB02", - "hmac_key": "152E43E82FC16A384EC3467EEE5B6CAB9A28CB31C7FD4E780989220D81BB68F9", - "adv_salt": "4FDF", - "plaintext": "773F77B30DD0BF7E16962FF93E85F3A0", - "ciphertext": "39A008F72CB3011DC67A472316B1AC89", - "metadata_key_hmac": "B41FC1515A21B25773032D7318A45DB772B5373B6E7BC7690E1AD7671EE98ACC" - }, - { - "key_seed": "E5BE2F0117C32F3E6476FE2D60F84EB86EC676468FECFBF0E5FAB83DA50DE853", - "ldt_key": "1AF39EB2A3C9A7C385231A254EE36E9E2889ADF9908CEEAFF6E642F4E301AEE49109F3AFBD0E5A495F614D0DECBD3AC21C2246B553DA4320CB0C4F0C348D5FD7", - "hmac_key": "898F388F7584FDF404382D080CD3F0F8164835A4026C3E9BFEA691BD42D337C6", - "adv_salt": "65E5", - "plaintext": "1E71789A9256C512EDE163EE6615BED688D90ACC293C", - "ciphertext": "72814ED024666464596FD640C5CDFC070A122B0D5138", - "metadata_key_hmac": "35F34DCEE430E78956E84CE300F70D8D16784ED1CA1F4E51D20FD0AD96D2AD64" - }, - { - "key_seed": "DEB8F3AB02D4CA40FA5DF4A8E0C755935C66113E49933EA39D5094AE9CE3C938", - "ldt_key": "5C51E916F1A2E55A7CC4167021A12241070FB268C481C5A442A341A339782AC383CEFE0ED38BA27C5E0950CFD98AB131C0EEAC2333B8A881F69F7F540D4174D9", - "hmac_key": "CD3C321F51017F76C486C86CE0909F6C1448CBD6356787EE2D8ED61E15993CB9", - "adv_salt": "B3E6", - "plaintext": "FDD913B0BA6F414E58EA34611CE0A4CF69B6", - "ciphertext": "C3534F67F05E0158BF61250C91DDEE5CC07A", - "metadata_key_hmac": "B68FCBA4A62F48821EE88DBA6C150ED4179FB22DBC355222DEF00BD9B7F7DD94" - }, - { - "key_seed": "DDE4DEB7FB1509B4B94BD641F49BFFE25216C7800BA49DE9774E0B3E00F6B1F8", - "ldt_key": "F0022155C9FE86F00157652A1AF200182D2DF9BA33D569C7B047E664C8B675C6A3CA7BA70BFC9FB42F0EC7B4031860B33A6127F777F264E10745CE34162E38D0", - "hmac_key": "EA0780167FC4307FBA5AF6E1E3DCDAC804E04E640C3E901ED314EC6168477255", - "adv_salt": "9F99", - "plaintext": "1EECAD555BBF19AE0466800BF45934049BAFEFC17F4422914A5E18C3", - "ciphertext": "41E6559722EEF73DA8D074CC8F16928B2A9E7641C8DE05F20E8E272F", - "metadata_key_hmac": "492F0C9C8785C62C7DCEDD1FAC417F955B655E155082E537294AB766B6C6D0A8" - }, - { - "key_seed": "44CB781146A3C78E6E8A208DBF6DEDC942DCDDB5DAE79B2AECA40A5D283E6958", - "ldt_key": "7D05A9CEB622104C1C613DC798EA67747C15045BFACC75FE83E64D1E559E9FBE5F8BC1A929938BA5163104CAB88BF8C351C9A80B40B8647C350D0C259E196BB4", - "hmac_key": "A876711C19F6F84BE72A67C71949E2E219334EA17808DE188C61CDF903E62888", - "adv_salt": "A42F", - "plaintext": "277FC7842DB8B13D285314F3970AC2F9C4566C", - "ciphertext": "791F4347A4B3480761E0EFC3CE606FA3A5DB3A", - "metadata_key_hmac": "019A49B77346288594C858C6321C99858927DC8244EC07980728F7898C53B9C5" - }, - { - "key_seed": "CCC6BBD4A930ADAEF8381C0452577F7E86C85F0C37F0F3F51D83BE608DAE9729", - "ldt_key": "050C71B86F9E827BE2E90E0145917FB64185B4D8A999920B8FC795D0BBA3FD5A56D955E7125796A1D2F8E411FB3B98FDA9F23AD5BFBC0936C073105A9576043B", - "hmac_key": "80D960AF3A480DA154E0B219ED87B57D1A16A82CC1156C4281F5EC2BFED99228", - "adv_salt": "3A79", - "plaintext": "CFC608FED7EBC2B62C40878DC32459D6CCFB3202787666", - "ciphertext": "407709B5E4025C8F6850F820E542B2CA448A895A12C17C", - "metadata_key_hmac": "B58D1908D6AEB8F13B67BAB587FCCF97CE502315F08FDA824A85C8B27106FC24" - }, - { - "key_seed": "8B179554B6C08F1CC2F308756ABE8DABEC0070D3B88E30A69A40CB7C0073D74F", - "ldt_key": "04CA9C627A91E340C3EE0035FA320161CFDA6E3A98ED48FA7025276EB65EBC61293246F65C1A856DB729CA1B8EB8429F976D016FF9E05619BBDBA6B7AF6FEF42", - "hmac_key": "F115187A05F7E99365B04CFC69025E64746C679CE382A5466030D2D36A84167D", - "adv_salt": "950B", - "plaintext": "263CBC2C39CE81978946AA45D2F80C4242383F", - "ciphertext": "A2AB036CFD8A49A0D96BF0AC8CB8FC30321FB1", - "metadata_key_hmac": "CCD14A8088B511E5D4391479030874AF78D51FDE0C7F3985DC91CCFFE7913A34" - }, - { - "key_seed": "23F0800D7FE07E42EDA7970AF9A3946ED4B71D4317E6275955840AEDB49122E6", - "ldt_key": "D91C2E9862353F094F2AB6710A11BF6CE9E77D2EEFAE85FA0327678CBC6A50AB428B9A844911590B7836BBD61E473946FE412668DD720042C5ECC60910A013AC", - "hmac_key": "5D6D0D8E2E3059E60004DFF0502432B3DB25E9A669BE95483103CC57179DA59A", - "adv_salt": "09F9", - "plaintext": "0EC8CA3BCF7D13FA317406CA74DD9518FBB4397DFF598C31929E8EFE5F", - "ciphertext": "B7D68C3ADF3500F84379B71FDE36735042A5D1B82805947C61472FB609", - "metadata_key_hmac": "10A7EC01CCC08C077A801221A6C5AFCBE2C7CD8DDC82EE6E3C7F7F0FD9A9C5C1" - }, - { - "key_seed": "E0C623A6D0CE4191239367A945BDB722BAA22D2E1A0D5247EF924D7C4CA68CFD", - "ldt_key": "F0803A39DDBF4CD032EB231AF6C0074B3D44940FD54CC95469D47BCF733AF58FD3BF516F018D93646030DC80B618E1101179AED6865F77159F36811FE1C2DF19", - "hmac_key": "E7D3F45040D509A1574A765B64FF3AB8C26A0FC6CF1D40F234FB09249CA40FC9", - "adv_salt": "2812", - "plaintext": "A72343C95BC54391FD228738D24F308CEE3D9A42", - "ciphertext": "B881F58C261E0D8C45775DB7C7888E4A7A41930E", - "metadata_key_hmac": "43AF65784B529CFF5BEC931118C36F7C70462D82B5F5888B0E78352BB2EECFF1" - }, - { - "key_seed": "0CDF3A201E6C43C1892D459351D83A5ABB549755626837458658615CF184DD17", - "ldt_key": "5400C8B5A3561E13619F4C8392575A4E0150C46607BE1AE71C09A2ED031BFC2857679460EC9E4477F6D79C34AACBB8EB385E1875469010A14A3D34FE47210096", - "hmac_key": "5C9A65AD78DFBE78506F6E39EB32D95783A760DBF18C65DDEFC4533AC2BB703E", - "adv_salt": "7EDC", - "plaintext": "3070FAAA1F5E0F689157D8E5BB0A5653", - "ciphertext": "05837C74EAAC8D82208455C1F9DA79B7", - "metadata_key_hmac": "058486F7D7262DC6162CD2680AF73522ACC29860023A7153210B2F17705C4EA3" - }, - { - "key_seed": "F4595E0315B783D09D0ACE96AF55E417E6B88EC9D6B019A55736C6BCBDEEEB40", - "ldt_key": "95E4AF265D858FEF7F15C542DBF1E231C0433634EC6B8D3BA12D5116897706CEEDBE8143D4A9F186C91E22F6E8A9CE05BC0C867323888364D0E86CB1FC9F3123", - "hmac_key": "F59932F5F489B3E304B4D055C368C851D0DAE57F82D338989BC2674B5966441A", - "adv_salt": "1125", - "plaintext": "BE0E27833763C0E7E4667BA54F0E3B2448", - "ciphertext": "9A4B53BF17C69A1B39E72C9AA89074894E", - "metadata_key_hmac": "A8F3AA49B8BA760F25991D609679553307DA29922A1AEA0B2CF57D1D7B28A6B9" - }, - { - "key_seed": "F0ECE6EC0A3DC55DF7BAB18C41CA0C9F5A0408FFFCAEF32D3081C9DB335C7F2B", - "ldt_key": "CA3E68D26BE851EBA1782C75D10EAA039DC705B0A44091B93F1729E149D5D1783044D9EC2528C13F08AB5AF780160FB59978B98605C1B45F7482BD6CF4FE89B5", - "hmac_key": "152FD69D75C30961E52263BFCC0CD5196F186543289A96D38E2D22662070EBAF", - "adv_salt": "FD52", - "plaintext": "101076F25A10920A37E5AA9853701CD94EDE8C46377923A8E7AEECF73D", - "ciphertext": "E6B61ACE7739628E83EA5DEBACA6E815455A68F9ABF5F02BCC41AD7CE7", - "metadata_key_hmac": "9BF6AC832411926D45BDBBCCC16DB131270D751FD3D77ED9928733E460740478" - }, - { - "key_seed": "6845EB5792CB894932F50C2CC19DDB0029A36F362318E85273BCD87DE2CEE71D", - "ldt_key": "E467836405D7A1899ACDC5BDAD71CDE12B2ACFD9A17CA9B643B3BC5D9DA84D4DEA9BDF84A5C511E0F0CF43FE51636A6A4D466C299254AF609E4B5C37DD7F65FA", - "hmac_key": "F47BF42FD2E4BFDB11832B25D360CE73F5DBAEE9EF9BAC9649B71B39A904D20A", - "adv_salt": "2B57", - "plaintext": "A411BA034E8A4BCCC3BB3EE9ECA169914AD28DFD2A621BC1D6AA7148", - "ciphertext": "0AE76BE8E290203BDAB2562944FCEC168ABEDA17360E8F6EA47E5031", - "metadata_key_hmac": "9F60DE167B3EF6EA0E0FB92FAEE7641D443BDB60AD83D823A485213183ECC301" - }, - { - "key_seed": "7DD79D618E3D46D6F2F568D4937F7293F0A7C818133A2A2624A30678EF97F9A7", - "ldt_key": "3ABF1885AA6693AE77C62F9C6DCE003F923B371A17EA6994F35B68AE9E29B5652E829B340BC3CF455AF516E84FA29041CAD7F8574D842BEEA84B683F3D6AC682", - "hmac_key": "7B672E9CF695CF0E3F4BE0C75D58FF7AFBC07E09D82B02AC609DD009520D13CF", - "adv_salt": "D088", - "plaintext": "209E53F8D180BA340A62BD7B6C13390A89E4851B520847", - "ciphertext": "86595462A4F6018EF97376786754982C920474A985A733", - "metadata_key_hmac": "AC1FA00AAE3DB0F94FE860812724A7DC602B29E89179D43253EAB0B1B31CDDFD" - }, - { - "key_seed": "886983BED2634BFDE5825B60E979F869091EFA35F4E4E48E1148F4CEA59E7EC6", - "ldt_key": "8D01837EBD1EB28BA3588908337F9B7DCDFBEC0ADAE46629B43B5B909C4A54FB63C67CF6E8641482A8C40440510BF6DEEE6A646E213A6858F61BC8BAB15D92E8", - "hmac_key": "410E201D89001A2308BA7395AF93031E09D275ECD2723BE229F0E241AAC79FD3", - "adv_salt": "752A", - "plaintext": "795B8C99EE3B8DA04522B32CCDF964C6", - "ciphertext": "BC830AA0C3C07AFB73EC43C341B472F6", - "metadata_key_hmac": "ECDA1D879E65F4C576C1B07C8AE57659F96863D1764A2D0F3D966757BDBEA59B" - }, - { - "key_seed": "3B6AB10F9814492725455760BB62BB7AC2DA22DE202649B8931885859B2DD567", - "ldt_key": "C8960538AE52B2AD074BA5EC0249FD22F6E7AAA000348C59B522E3ECD6A35C9A324A59D1DC734CA0228A0D43AC9F8E809F65041F2F3BA7A8227335B0C5483CD3", - "hmac_key": "ED3470CBE882DD7A2420F9EDDE8190C182BDD6F41A05A93BC7F15F70324DB9B4", - "adv_salt": "3BB1", - "plaintext": "9D5F7599D4B4A44B7B8B75E64B3371882AFFAE8F41B87238E1", - "ciphertext": "1BB10248F26B45704AC0B1A02D0F700C6D4D10713442A15DAD", - "metadata_key_hmac": "FBF4F33EA32E3F888FBB55591CE60BB9844C92DBFC9A8BD54ABE6AABA881CCD0" - }, - { - "key_seed": "1FCCFA2BFF7C4D711678145842EE6575F5AB575095C759F4D02AFE2EA8BF613A", - "ldt_key": "F5EAD66A08A058B727CFBA95FF6BEC745AFD0507C7E4567547CD8C44786222BAF3E77CF5C1CFBCA0DF6035113247F7B55F248D78B24BACE71AB3FF154760F1C1", - "hmac_key": "948A90DA3B1BCF09C1F363E92FBED428C25514E02B7D90DC1D58B116DC930AF8", - "adv_salt": "2A58", - "plaintext": "62C4B72073C76C3DAE8343EDF66F5C492E4978C67C199149", - "ciphertext": "510260D7D04687D5E1E92A964360FC145FA20C5D360EE8E1", - "metadata_key_hmac": "E030F6966A67F333E6FBCFF6439EBFECF6BE0D3BB7E9124B3237F1B4176F8BB9" - }, - { - "key_seed": "A00B6671AAE6906C1478CF7BF2F6CD018E0C93CC645A0F3A14059E820FCC6AA1", - "ldt_key": "5A9C17410FF455E4C62E97605CB9FD196D5CCBE42EB9AF3AFD9B5302DFEC3CDD400EC95F5110CB95300E58CEEB85AB81988BEB9DA6E533AFDCC27C973F8C8592", - "hmac_key": "8FC128773B31D7C6B0CEF342DB3B958504E53445CF14651B8780D90ED83B8EC7", - "adv_salt": "F08B", - "plaintext": "06645B1F8B0099E32FF1F197744E4498577A", - "ciphertext": "685DFBBE76C2486733AD7CD5F11F1D1D0431", - "metadata_key_hmac": "609702A78C0F810F05CD25E1B42D992F5162CB3348281E554E1CB2754D71C7A9" - }, - { - "key_seed": "9A1EBDDEDF77B01E0F9389D406C640B64F86EE57F142A8DBBC336B28CA9ED9CB", - "ldt_key": "84A871D9EF570E2D4022DF76A346526FF77A203CA24F159E84DE68253BF42E52F73522ABD09ADC290690D3CC97824494FA5B7C1D57F1C9660529918A08F8663A", - "hmac_key": "7451E1A8C1E351514AA3D427030B55F54A117D9D2E06CB53277306D8EE1E81AA", - "adv_salt": "3AEC", - "plaintext": "3E8EF057611BB2A24FA9A1FB6277BB5E4834", - "ciphertext": "6747ACD188E8E81E68AC103B54B1BEB0CB11", - "metadata_key_hmac": "21F87E9AABB821F059BE8428083A3E2D5C921D6E3C334EFD996AF80537EE2347" - }, - { - "key_seed": "02BBE706B5607F60E480E1B313751D9963D8D62C85B04701248DBEDBF2E95E6F", - "ldt_key": "C674CB7FEA75105EE6CB2287E260C7D4F1DAB9637E4ABEEB9DE0201EFED078103408986A25BE5136349D9E9DE49651D73EA07A1834D5E9F9347177051E153D22", - "hmac_key": "8AE91FD62D9BDB9D876EA454B0514C1280983A0D4FEBB5EA2D1E8D859D9A872E", - "adv_salt": "00B8", - "plaintext": "85ABA9ACA14B5EFBCC63FFA1E303F13DB2CF78D4D6124395FAB3F1E28984", - "ciphertext": "876DE4842160DBCFC8E2FD5F18CE573060B850FF2FAF0E5CE2D65534B7E8", - "metadata_key_hmac": "9560019ED9FC93D3D744EF250DA756AD5A394360E55C95E1AA786D484EBF8FE9" + "adv_salt": "63B3", + "ciphertext": "E274427BBA4C12E4FF1E03193096450E8F8849A6CBDCE3", + "hmac_key": "72E8C574A8402765B5220C5FD95292DD3C7230DCD6E78EB5171FDF68FB6B2410", + "identity_token_hmac": "735F48DAAD03872E8E2C9873F29DEABF03BB0E174F62F679CD10F5BD021E816C", + "key_seed": "93291E25813E14BC2A72616946D7A5EF03BA8292016307ADA7D5533672D25C42", + "ldt_key": "D5FC26F6C1B3363578EB84386B06169CFCD2800582F8E3089DEFF90F04C39C92F2FC98DCBFE9E696AFFD308FB0D7D60B0A5CF2A4CCEE7748F9B4BD3D5288A1AC", + "plaintext": "9D799C298ECC149A0FBD23D0B5D7532872748782B8417E" }, { - "key_seed": "4EA4AF5C49173C1B8AF0F28E15A1C539398591A2DD0D0179438A4A46FA1E397F", - "ldt_key": "F452E293CD698F02560E44CBA21D124AFADB3E75290F915F41142A6EC7E0F729202F11629A2C7F54420B8A5D5E488C88C9303A908F7E398CA9D85C22CC124DBE", - "hmac_key": "3BFE522958CA6DA64492B62B079736B32733108A743A3F308B3B1A2EAB6F526C", "adv_salt": "189B", - "plaintext": "8D054FBE40F231670A5E5001BC68B1852E", - "ciphertext": "64398AD9AA2327DD94DD55D3B662261808", - "metadata_key_hmac": "E4063B38746759C4C29D9D2DC0033DA320B107C07A778AAE5BB7E4F2AE096394" + "ciphertext": "2A178D14AC6AB43A4D4CE5518DFB18812AB5A775A92C53DF", + "hmac_key": "A4EFFFED83FB0970C2AC5D129E96559D2CD556DB229CF5B6577847EC214370C3", + "identity_token_hmac": "95E77505F78C78695FAAFB6073ECB7A19CDBC343EB3111927613E21A12430A08", + "key_seed": "3DF510C1EC101D1F4A41D20932E9503571EF92898C34D6A291D6AFBCA96D5982", + "ldt_key": "CC2E135B687B2D841810F96B9DAB9A6A8F32335A5A9A224FBE6ADB6FE742F157E91F2B397D4028F9F0CE20FB760F8870AD295E29A1F9DB4BB85CAC876E220560", + "plaintext": "DD2832FC6623AA56C4BD9293B036B5194D676566DE94C3A1" }, { - "key_seed": "F42A1BE211F5C2E9E2037B43CD68DBEEAADFE69EAA443F9C8888370176C8C543", - "ldt_key": "002B3F92CE5D2020CB4F0E184A4AC41F5E948C61DE5BBA9AF06CC0714F9D9422B0C3E222A2DB03945BDD9451BCAC38E49A2B9C817F1D79F84683992DAF03BF86", - "hmac_key": "E7C31AD4D5C82B23BFEB4B6E41123AAD54AA49894C0D7F2D6717538C75EC5894", - "adv_salt": "B827", - "plaintext": "6D2217B067C2CAA899D22621D6D4FF1040B20A59572E7C90CF5FA1", - "ciphertext": "CEFBDF5AE9BF0AFC44758F0D16BF786DF0CB4A8162A2E4D37C7B95", - "metadata_key_hmac": "859138DDCBA951BF2A1A55980EA925FCDA9D2C4781BE9F0EFC3AC5762145FE9B" + "adv_salt": "4568", + "ciphertext": "471CD1F0BBEF830CAF51C91D58FF285107B27FA6E3A7BFF2C747D2", + "hmac_key": "EF8EFD105D39D95ED341D23C9CFBF1F946C894D9E56FC1E2D42F0B6BD91B37C3", + "identity_token_hmac": "16EA251947E144EE1FB14C3233A90E5165CFF4A35A2BBBC778FD1927C05ECE2B", + "key_seed": "FD10C04D5266C0629A5591F158B94F4F27F362F7CAA0FC65FA9C45B15A368B11", + "ldt_key": "BD876915705EAF5D40B71C13DD21DA541443165C3590502E8E833831C6DC987C86E6052FA0F46133AA9446807CE761C337711F6572D80F02F3F0F7BD7F399351", + "plaintext": "7C5456D3085F9292D5B3A4C74FB3A94477E91DC4ED6E34EA36AABD" }, { - "key_seed": "AE01D3D7BAB394780FFB0C8DFD142473558F87796539BA4FA6B02E12A886A790", - "ldt_key": "7BC9A4C2BEC95850FE6DFD7BD9CEEEEBF0AE4FE3AC123C499E0B49D1CDFEB8F1FC72A70C8D7E764E2EF451DA3B5EF65D1B9467CFA8B5B4A958E882A8CC6A19AE", - "hmac_key": "D25F40424B68CB9D6D6FBD421C90A1B7011281B90BDC624B506A797548DBEA5D", - "adv_salt": "C420", - "plaintext": "A1E9E22F5D43C023AFC9668C85062E89D811E169", - "ciphertext": "DF37010A01172778F61742924B5B512BA0A60B61", - "metadata_key_hmac": "F2A089D75A15F0D3739A51A2941C37A661546F63F92B9DC218C754AC4329660B" + "adv_salt": "D733", + "ciphertext": "D34FCAF70EE1A3B16F39DF081F2B1E18BB6BAE100BF9", + "hmac_key": "E2CD0A84E585324F74B14760CED8FA3E749230B8EB52D9482626A2BC79C419B7", + "identity_token_hmac": "392EAB5592B90BED1C6D8148324B6C6A54A2970A7E6E8AD84F9A1E35B00C7FBE", + "key_seed": "3D70F1284B2007EAAAAC0107E63A5E29DFB1B951BF67F74A9F454C1540397466", + "ldt_key": "E2C0B7987BC05CC4FF3AD406421FE70F65682191708A7C8BE2B0CFD35AC7EB6A014CA36540240A83C202E1F8C8F64DFB201A85A38FE0DCDEF5C7004DBB2BC6CC", + "plaintext": "DBC428E33858278C6190505B43357EAF0AF3569BCEC8" }, { - "key_seed": "70BEDA5EECC8D3DE9279AEBF08821AE91597C809492A5DBCC207D05CA24EDCD4", - "ldt_key": "87E82E7F869CD2D4BF48A8E6002FA871A6400C14F4603C94B7A6908669DAB1A4491DFB74DBB84D807907A22CF88A334B5335B4011D864467CB555B1564903A31", - "hmac_key": "1BBB2D77F26FE5F04DE6DE0CD30840FD5D5027B7851F9CCA2C7D63A0F360016C", - "adv_salt": "770E", - "plaintext": "47D9F1849D6694DF22FCDF35B98EA7A539345EA911", - "ciphertext": "346E66B1735597E9F8D23195D009972A120D63BFA0", - "metadata_key_hmac": "269F952F828590B58EC692CFB33476C07400989E1C1BE1534FC8FB905C47ACD4" + "adv_salt": "A601", + "ciphertext": "BDA9A063CFFA5DC94A6F079309148F736EB30730EC334954ADFB96", + "hmac_key": "073737D4AD528AF8DF09A400A22F9354732340D628A910A7ED2DFE439780D37C", + "identity_token_hmac": "752A241BDBD62ADA62B55DB137A812A81530F6945B347A72E10C9DDD3961076B", + "key_seed": "23D63C05009E3370B196DA6FE4A96E3E38594F3BA0383FE19B727C682839ECF8", + "ldt_key": "CA7CF088A8165728DEB146ACD30061FB7B5C5F17ED53445FFD3562F4D520AE4FF933F76774DFC0D3CFD4E4385FE57092B92D0AC4CBAAAF3C16483D12DCB12BF2", + "plaintext": "95A5877E5F58B6D995B2084E4F38EA8ABAE4BC83AAADF04DCFDB57" }, { - "key_seed": "D507C742BA65C365B140AB279E7D5BAD07828ECA90E1045D546D4C4CE09ED6D4", - "ldt_key": "3C68C30F21525DB68A56DB84A99A2B0050B64F680C7B642EA0D85DFCA3BF6B18D84BFE8661033FC77A3707F733CCC7FCE6D782BD139A2B722030F48BA0BE3D61", - "hmac_key": "5FB552390E176EB1197E73C1474E889A2F85239B953FA0954DA8CECDDA64C020", - "adv_salt": "5267", - "plaintext": "9FCA0749B49D04C8E5B32A6DA1A9B52B9B1954FDB59CAD", - "ciphertext": "AE17138F7C26808A840A009F38B2BE17BEEF6A5DB9F655", - "metadata_key_hmac": "AA31DCB8A2C507B89209B1B37B19C136811C5467C61DC4D0D04EE503A4D390AD" + "adv_salt": "AAFD", + "ciphertext": "8803E1FD58511E33AED43339A9E0077C7012", + "hmac_key": "3AD326F0FD9F9E3C6216293F046E8E3367A218A0875555B50792368E9A7591D2", + "identity_token_hmac": "EFCE15BDB07640F9F2B81A42DAAA8F5C5580FC94295E154B8A41713CB89F27BA", + "key_seed": "DFC2389FDC8647D1C23DD7121A2DFB7A8BCE9CC9F69F50629D5338528BCD79FC", + "ldt_key": "4A7D987807CAD0F173ABD53F0A90D9DE1F365EE14CAEE6611CFF3FF4430C07EA7607BB3B7A56AA3FD4466541ADCE1BA06B7B55D4570E7AA0E329B20A307A5F3D", + "plaintext": "3905F15E8C081BCC6C9E5467578785CF8DC9" }, { - "key_seed": "082C07502435C163C687BDF0D9C6F8C058125E6A957966A860C4C8FDE3BB76DB", - "ldt_key": "0337020D34C0EAF110148BB6CF71ACF77DEEF96C9097AA0F90606C849113FC8A3E02E840FF6DC12DC4C9E8C27E2CCA6D6A5429403C1CF04198670279F1A27518", - "hmac_key": "9FC12C38D43FA05ACBAB2A411E332B76274B0180BB670098FFB07327E96BB0FD", - "adv_salt": "91E9", - "plaintext": "2C40CBC0327A6AC756BDC545FC7656811607F325A6322D6CB0FC", - "ciphertext": "4905857773E7C38F6094B77491AF04E07135A3DBBFD61ED63D22", - "metadata_key_hmac": "745F00AA5C29AE6315E07C0AE2F7FB10C07C6D9F24E81E3F22921EE37159BDD1" + "adv_salt": "6063", + "ciphertext": "41A468606A9285661FA1A0E0641A1235", + "hmac_key": "AD9E86FD3ECFF585047BD57B84EB6B42B2FB6E6F6851F2B23C4D6F45C5F93989", + "identity_token_hmac": "BFC8B274D5CF97006B0C393C250CF9BD22FA71C26D8ED1301BB4E7F8BB4AD034", + "key_seed": "6C45D420A250B3F9EF075B78CF04C274C0C45CC0C8ABEE8D54740A4471628048", + "ldt_key": "13F9A8A679153671E1EEE4AD451DB5A32B2FA72FB57855FF99CAA454CA68910D27C9B7F7C99E1D1D16C4D3D07E7756BB822948DE982B322E6D3F536BDCB9C364", + "plaintext": "E8B1174511617F08A79EBBB2D4E324F0" }, { - "key_seed": "9AC7DC14A8E9F6E17E98CAFE93607A4A018752248988A774F3D41DE4CB7C254F", - "ldt_key": "29DDAB2F42CA51EB35DF34053AFA8AD4304A5264C6E662D1882D91835AB747AE8BFA778125F3BC64C227FF8AFD8670AA64E546C12C6B094BB7080E0E6C3DD029", - "hmac_key": "055323B77EAE387521938AA096C573535B24FE81EB659C9607509674228E5398", - "adv_salt": "BB35", - "plaintext": "47887D96343D6575BD51502D25E4D6F549B9", - "ciphertext": "2051416E4B88A1406854EB29067BBF4692F7", - "metadata_key_hmac": "6FFE9D0276F20DF381DF22F7FD691C94DD22B5CE0D83C2C7C10E92E55AF666A0" + "adv_salt": "B09E", + "ciphertext": "66BAE514FE9FD3D4FD03943B731DFAD4186410673A19", + "hmac_key": "2B631AD159E8B1D7C4712A1C1D2E453BCDF2A9944181251928B2F88C069EED97", + "identity_token_hmac": "6661D3B31A9CA7A32994E35FC3DA8247B0BB26CB70FA76A91E69D271D365FA6B", + "key_seed": "A958898664C9EC450FAAF215FED0AE4C08E7A9AE8AEB547200687BBDC4F2DD6F", + "ldt_key": "34F34990D04CE8CB5B2CAE7B4CC5C772F7F3074B8348133BE384E5A40C179E91AF3C46231D464071757ED5343B27797D82E15D8D4651CF65ACD2D371F3F9D06E", + "plaintext": "3A87E4A4C1F450753A330CA5A2258810222C38337143" }, { - "key_seed": "A7F821CEAB3B6D1D7FC036EC3EE7D3F4417A5C404E16E36D98101AD14481E509", - "ldt_key": "911E5548B9158AC32DBD213D4F13F38478D1D53B18E97E349675C82ACC9BAAC7332064BA5C46DAEDEC560D4CC61C23A82EE1D6EBF2E5034244A1CCDF32608B1E", - "hmac_key": "ACFC4DF4EABE77E22C04E1D350CC8E68436A422B7868C0370CC3B2B308B8273E", - "adv_salt": "E921", - "plaintext": "F8AA31BC1DA3C4ED9A8D67D1231695174916CDA64C2EF1", - "ciphertext": "ED4715C57B04B724A3931C0917325EBA202DEE87087658", - "metadata_key_hmac": "1276F63BA4A898834F61208E74169B5CFD856DDF96483012D63B8DF05693E8ED" + "adv_salt": "E6BE", + "ciphertext": "94DACA62F2E46079502E34FE601A765FD9", + "hmac_key": "0028DA5E27469A75C6CC83B6ECAA730F4D0C967107B3B1FF7934D8AEAFF59229", + "identity_token_hmac": "D13D8500C5A0B2E2B102B66D0F9DA33A69515F8FBDBD7972B456E101D921C5AF", + "key_seed": "D201C792BDDA73C0ED08AFB789EE1BCDCA1EB65784326A053AA860913FB01109", + "ldt_key": "7679881D455CD5811BFF61F1641D7A98E9C1EF6D29C27FAF6FAA39A0B5F5C473A5A2928EE721EB74491E0265BECDD88B67EF14E180A7F2387067113D32C0B607", + "plaintext": "3A10B1E09860673681B97E613F83A31EDA" }, { - "key_seed": "05146E31D1D116189449455E6501366FB98EDA901511C8313F87B87851F50CAE", - "ldt_key": "A336203EAE0CF9F55BE6C666C794B600E167F53F38F8386BFA167F26ACD924CC8D5C86CE9F5C87EFBE3EDD8951116AF5197809D0AF26FBB1BA6AE73CC3E87E70", - "hmac_key": "666994FCE84DB1119ED4B98A3C7B8E90F3254B55762A384488B1102F090A2447", - "adv_salt": "C346", - "plaintext": "6A6FF037B5E075C69901ADF42CE1B49277DB", - "ciphertext": "34893FB6D8DF991304558F1CB8D595B125E6", - "metadata_key_hmac": "1FFDBD41802C5F9A5976342F548FC8B49015DFAAC72858B227B55BDC3CFEFFE5" + "adv_salt": "137A", + "ciphertext": "6661D85579EA7F0BB4236F4970226B920BFE9972", + "hmac_key": "18F7FD0D50302C2270E2B064E774C3F29C7F8D70D97B508E4B8779615C38A408", + "identity_token_hmac": "9DE247481C8E8522A87AAAD086780BA8F41C3A77FC9D8DA0BB640BA33BCB84C9", + "key_seed": "5DDA71768B7558FA3C98B3A29B47FC356B6B6DA5754D75689AF29617CE80AD1D", + "ldt_key": "1401881423FB090F773116675B1D5D3DB5380A30CA6342210E4BF415EEC78CBE3503049F2B6F6C2224324246044358467BC653FC10816153B30637879910EBF5", + "plaintext": "0DFABA7AE42D7114DF5FB4D42050BA1CA477E806" }, { - "key_seed": "CB8368E78CF6BFF4E3F38E01C35D5EF9DEB72CAABD28173DC4DE59C8CB4D2ADD", - "ldt_key": "A006ACEC50B59BA7B05C36121C3029E0D0C15AD9A644B189CF2B193B707856347D692798023A4E30B7AFAA3B94F83F1DE1C806CD7FFE9F94A95BEC6620136D3D", - "hmac_key": "AF80B241E2AE4058794F8116C61E874AF7EB72E44521C1B88BF5D01B8EF89DAE", - "adv_salt": "2DFE", - "plaintext": "3ED1C991A0908D7D6A9F600038ED4020EFCCC3D9BF", - "ciphertext": "C17E5EC275B2C3815E76C6993D2ABD932E3F931CEF", - "metadata_key_hmac": "27347C08628562703834074132602FABBC18CF047E80B97F45D50B85348BE112" + "adv_salt": "7A27", + "ciphertext": "FE25721548C2E4C274F522F8F074743F9C58D90272DD81B5C08BBDDE7392", + "hmac_key": "A697350A4735005470C8D00E436DCE30D93D0EF7E1320EDE756AC076EF155BF4", + "identity_token_hmac": "CB23C030952822E5164C08ABC71C02E79C84EB317A952F42D8CC806C3677257D", + "key_seed": "B53B8AC84CA27A918A2C79425215E934D0E1AFB20FF246B5A7B5F2212CB75D03", + "ldt_key": "BB917A8EAAF7C391CAF0FF971AB3C8D2506C499CAF697A4B1F4C9761756998A3C9C752B535B957AA535B9849024162B2816E833F71E7ADABC568E384A7D166A3", + "plaintext": "77FEC4D2BBCEDBEF542E144D26FEEA7418969B2013A34F48733FEB89DBC1" }, { - "key_seed": "47B05B1B7078EF2CD984B694BCE4FE8ECE2763F4BC9E5773DBCAE1E6CF907351", - "ldt_key": "5B018A74552C4161682CA23AC77A96209F9770294B125754CA8C31BEA3E2587EBF599ACC841494CBCE2E87EEC76D7BCD678F637988A28AD2523E5BAF838D3D28", - "hmac_key": "2AC31415141949B576D62AC0F09966823D4513E4EC90AD3BC1ED496B5B256158", - "adv_salt": "286B", - "plaintext": "2D12BD3EC6C4EF5F72116F3EF10602D1CD03463E3F8B", - "ciphertext": "E18B3A18B6A506A10742ECAED5C74B5FA9A9008D0CA4", - "metadata_key_hmac": "3A8207005DB61BEB73F1614EB70BC5D1BDB3C231FBEBEFDBA8D736C01BE563D9" + "adv_salt": "631F", + "ciphertext": "28399DB082C882B5B71AE5F57220B2FB10BEB0E317F0BEB0F4FF7B", + "hmac_key": "FE628D81C280912E866EF534EB73D3D26A2791C4E0348A3B735D4F6A58A276A8", + "identity_token_hmac": "87DA1BAE46083903B09A26D07D33D4E8A05FA6F766DFC16F5EBD1952D10CBAFB", + "key_seed": "9478B0EF762A5F474D2898CCDC23B2D35ECAC488AF848F204F18D65082EEBB49", + "ldt_key": "5E52F197C3EE72434BC12849DE8F4460E690F1BECDD676D7F5066EFCB5F2FED6D11CE8DFBCB0D5A44F5A10388756D0CF468CEDFF2E57EF37ECFAAF790C0A70B4", + "plaintext": "CDF16A05E3D0F01419E9A9E197CCEB77A94B8F0875A18EA07CC471" }, { - "key_seed": "A731704EDABFFD225672895853D4CA8FF477C9D65A37552649DE0AFD5CAF9BFE", - "ldt_key": "471AEE153C461CEEF36FF4F7ED324EBD360C4330EF9041DD15D87F36FD49BC142366F26C20A388E8EF31B19E3E503721B3039EB39EFDDE3EE0B1AAC921480AB0", - "hmac_key": "BECD2B6C5469448FF69DEEEF6C603F1DE94DC9597A5F064BBE1F4C23366A6740", - "adv_salt": "AE19", - "plaintext": "577BCC8E5D86ECA8F738DD611E297E41ADF149F88CF396", - "ciphertext": "4204C7C25C7F5F823B92B687FF977E1561EBD28227FE0C", - "metadata_key_hmac": "00D88C16275FD4D4DFB56BD64A3344FBD50662A5AD408702944FF77B4D76EDF8" + "adv_salt": "3C06", + "ciphertext": "F3CB6C6E54F5404F710E395DFB745EBAD74532E3DB38CA69A77DE120EA2BDE", + "hmac_key": "97DDC5B9315B1DCE1F1B60E4243088953F35C485D20666ECD42E1ECF60346B69", + "identity_token_hmac": "3DCA4C5B3B8FDB8FAD3FE7F32C307D64555BE8ACD2447ED2FE95CC21990E3E15", + "key_seed": "D5C2342B100FB4C81AE3820F3C5B5503B089DC3FB065B4321D6CFC3D1EB82D1D", + "ldt_key": "983EFB98F5FA2DB96CA7D2A173B2CC03C926E09BE575F3514601E997FAFE4742B4294FD020914170E190EB3399470B90FC790ED7168A41DEE95738EFA119937F", + "plaintext": "4E1C99C2D02E2F9D6453224B8142FCD71515FE2838B6E7DDFAA7035D65B433" }, { - "key_seed": "755BC50C45FA7D7F512DB0251C28C61093DDA9EE5AC3444E5265AB773271D211", - "ldt_key": "FEFDA5252816E78E13CD349E56C6D5C392606AA02E9BDFB50C6CF72FC4C728D894D4C6BB5E4709AAB0726B39AF1F3DF0C6D8896F16078E4ECB0B695F8E23BD33", - "hmac_key": "7A732507A869D82418C6657721DCCBFFC49EF3AFB44441C93F097EE1DB47FA37", - "adv_salt": "21BD", - "plaintext": "851D152EFB5AA2A792221DD11836E2BB1553ECFA1AAB8B83C48770BD91", - "ciphertext": "671C99E29BBD8AAD0DFAA6504229D28639C1D5224831FC056F72648D65", - "metadata_key_hmac": "4FC52636E718CF7D85B429CB734EDEEC7559C5B7A136578ED05E4ACC9B6A4CC6" + "adv_salt": "0A54", + "ciphertext": "216826E89337FF9C8C86A88A7F9610700886A36AD7CF767DA31A15", + "hmac_key": "C2B74FB5BAD82E56CCE52FF1E11F513F32528CCB480927EE74E5BD7CAB3FAC62", + "identity_token_hmac": "AA72967F9912971CFABB6C9B17C9A7F6C87A37EE2C239EF17874D00B1B5DE61A", + "key_seed": "0DB6C6843FF10D5F38F7809CB20D4D9E46497EB1F1D2F0C675021EA734EEDE03", + "ldt_key": "62513FCD2578DAB8D8C234E893EA8A1B6079D8034607F2B0C1DA3C062D5A1D8E40FCE047E785E3EA31287CDB59B27E4F86A35C9231EF03611BE8CEC4EB3EA511", + "plaintext": "0A17149A84904755A19D9648902C10CC407A7B75E20AD94B9524BD" }, { - "key_seed": "2C9FEB9FDFABA657077CC7877C65FE30A257A58704E73F88A6CAFF9153790BE5", - "ldt_key": "F85C764E4D4464D0DB36D0F0F463048EFE2089111630D8E9B7758657189730B9630B9DFA4374166AE2F79BFFC5892AFD560BA2196E219B5A2368A21DAB1C123E", - "hmac_key": "F5289C28A60DCB53CC4278D34E4547514C61F504FE0F64F63F46340E3A759034", - "adv_salt": "3FEB", - "plaintext": "AAE2E09A0CB648FD9486FD845608F02766A9AD46F1CBD1287DC7BD2B", - "ciphertext": "C060C326622F2E899B721E08B4B2E7713FD738911443CE134C882F91", - "metadata_key_hmac": "DD496B4252BA8EE1A78DD00A3CB620CC29DF6D479B7F0B1E085EE1EC48AA4BBA" + "adv_salt": "8BE3", + "ciphertext": "388AA1AF4F579F96D9EE856BB4F6B3E17A242BB8A3E65688B1DB069C65", + "hmac_key": "4FCB9A35A2D7B4DAF8306AA49EBA5381B4B4B06BB304CAD1D2A038A7458C6A2D", + "identity_token_hmac": "3C6FD647D8723484F82C9A5030B020208FBD0719BC7D3D442B0D3144F0F91471", + "key_seed": "0DB07D210A15768D1570BE426E0404A907C6DE2346541763011C190939FFB3AD", + "ldt_key": "A402A13DBDF763065057DA78E634F46E7AA40B5957E4BC1C50A22CEDA9962C6A7EB4EB1566DD4A0394178F2B295E77AA044434AE2484512AB3D1EB57CD4554BF", + "plaintext": "D806CDF0B1B96817469D15A96448262DEC4A6BC167CBDA5AF46DA97DDF" }, { - "key_seed": "DC0777F5390257D9662BEA2774088154796EEE18D2C6B6F294DA87A692EE590A", - "ldt_key": "544BBFF963DA99EF4C467967375B940BA005DAF5C67407ADE630A000B7D49D315504457B5373A7987C6CEA690A96D5F7BD6E313FFE159300ACC428F3AB9662DA", - "hmac_key": "3D37F8B0A5CE29C00D5295B2BB40670E9F08D51C020C722CEEA7CA0158512DF7", - "adv_salt": "6643", - "plaintext": "721FD2BCF08DD943D40E9ECA4B25FC810E86919F31", - "ciphertext": "611522B0F0950EF619157C921ADC2D134F18B93C10", - "metadata_key_hmac": "6A18A836A710EA43DC92FD5321ED90893EC229FD1E035AB776E7E93252C5EA7C" + "adv_salt": "7F11", + "ciphertext": "ADA4507A0043839EAEFB25E918F35BC2EF9C802AB9", + "hmac_key": "E45BE5793166A4AECAF49E88557A396772FBBDA6991CB7DF747C66D35C630071", + "identity_token_hmac": "664EE5E73ACE23F1C2ED4109B1A790B5D79CA3D1199F72D17325B4773CBCFAB2", + "key_seed": "189EB21B47BD26468B2688EF969AE3CAB335F851751754499624BF2ED101DD0C", + "ldt_key": "62BE54619E90A085C9033E75D0A0E4F80803CF8B21FF4E0BDDA00C91F9B65D1E8F689299EFBF3EE03758B182D0D4C81B3A37B181AB3B342686F3202552E25D36", + "plaintext": "1ED2E4DCB9EBCE51D81DE2440A88F8C4218EBA7880" }, { - "key_seed": "6FF7DF107A419A8FB65097B6B2CCFDB1B92757E72A1538B9C582D5C05C839E91", - "ldt_key": "AB2A2E9622BF63CFFA5592E1EC7CA491ADD64E594C7441D45CCA381B879CDD73F79DAC43824EBCE0831F4B4A2D9D8A0699FB11FFF3D650166B8353D0D86EC30E", - "hmac_key": "C2730C47227BBB11ACE9FD69F0F716754CB0ECE8E7AAACEDD1C3EDF0A83E0A24", - "adv_salt": "E652", - "plaintext": "7878A0505FD09850B82EC2404E2847984026EC962F29", - "ciphertext": "68C40846FC1269959427C29BAF7275FAB70FAA0EADED", - "metadata_key_hmac": "AC7EA05D26A200231873CC00D02CAB9AB7FE74F736FB3136BC4E8770164BD89F" + "adv_salt": "E78B", + "ciphertext": "2750A1DD26974816A86F25D21A77BCCE7D0F162BB02A9E", + "hmac_key": "A6ECD71B681206038FEFE976CA6B480B3EF9C96F97614BEA5F97EB02F6F9FE0C", + "identity_token_hmac": "E233B0BB2E2042D6F097325B9D56EA1BD328861D76F670107FA18B46E509BCAD", + "key_seed": "060B02CC1ECFA8236FCC5573CB4900AD652913947000F1062571AECB42DCEE3A", + "ldt_key": "D2849561C2C8FA1A50CAFDD0CA727EE277732E942148B7BBA670F92C8AA53C42B71E332E41182EF28CA75285AF0692992E49A5BF049BF775181A15E2A458169D", + "plaintext": "C4D8C9B754A01732C3CC63D10E27CE3461F5551E7E43AE" }, { - "key_seed": "6E12D74E582342F3308E467E5D702F3E5DF4240AAC170FE6DE888F3E0FE11EBC", - "ldt_key": "2FD4BB618D3BDD54E8D6E6E2B15FB085C8C38A8ED13DB81C8268BC76D76D5B98406213F8BF6435F9EDCE9AF02CC9E62C8A1536A3557AB946899C334558D8C86B", - "hmac_key": "72F271C80646ACDFB7D085B044140EC046910B5B707F0E29C0A3F9A5969A37D6", - "adv_salt": "59CA", - "plaintext": "7AD1A3957A05FD0FAFC434FED374579451F308F7FA33AEA7", - "ciphertext": "A50CC7B88D02C6787B2ECD0EDE9EDA564AA9CA9A2319819C", - "metadata_key_hmac": "8AF34F258AB3404A36828FF1CFB017D2044737F4A8D9DED39FCE9DFC83103ADD" + "adv_salt": "EA65", + "ciphertext": "57856CB60C92E5705AFA37A9831C7E2C0A", + "hmac_key": "38E27F67F0D0906DBDED17915739EDB44269B0CE9B20A0F9581F1CA16611D766", + "identity_token_hmac": "5F03FC11FD378E7BA7F0F076EBDD920A9227A7A011CD4B41DD6DBA50442D1A9E", + "key_seed": "BEEC1F791F0F46D638D543B13377B0BD8440EEEB8FB0B0609EC973EF694E5AF9", + "ldt_key": "9696153B6F0C612EC4C651751B4A236ACD4301DE680A021BA123286344D26543ABAC4905F32272333D1EB6C34E336180CF1EB4BF3BFD49DF1E856BC1B6835FC5", + "plaintext": "52F5AD3522DA1CB6CFCAB587B86E9A3E30" }, { - "key_seed": "C8A294318414CAFF7BE91B7E8E671D1518B6C3F33ED3AFCCD0F48BE1E2C45D65", - "ldt_key": "0C03E2C14C0E304D6BB4FF746FD6F9C1094A6F46F141BF85FD78963C536306DA08C3F8C69BBE4A6EB9039F6DD7F34E11D0727DCB5E4D66C59678C368BB9512D1", - "hmac_key": "3495F1515C76C2B46FFD402C31D06C3BB13A4364268394830AC39F2003925A10", - "adv_salt": "7503", - "plaintext": "FA03E156319548EA54E252604D607B9EA4955D7497D0", - "ciphertext": "7D94D5C7B8BBB8C9C180E6C61AAE454FFD8556E2B006", - "metadata_key_hmac": "137DC239F65339791D617F036502BED994D27C084EF0A180FECDD9F8ECFB04FA" + "adv_salt": "AD59", + "ciphertext": "1F00BB7B0B050E10774747616B67004D03396ABFA0D8ADD0", + "hmac_key": "552017B1A0E047B5882918EB3A438A5C9A4EAD2A38353A9C64F71527DA419BA0", + "identity_token_hmac": "DED83CB27AFA8D5CE08D8D1C05C6385C9F6B96972351EBB8C9694894DD310537", + "key_seed": "11A1E82D6BD216E080F4DA502D4F62B406A99DE2296F83657C2731AD0F7A9DD7", + "ldt_key": "EAF9C2AFBAE16C0D32FBF91FF969D1EE7E009CDEF0084DC884354AA623A32DA581776A4D5E58FF70B17DD532482C1CCD63EB9EE362869E39EB79D7B305F3DF82", + "plaintext": "1BE6306F08E53128A20DCD8949CABBA76FB5B70937677545" }, { - "key_seed": "B400D12BBA0D31B81B68983E87D7D63F768456601EDA03886E67C5C82B2C167A", - "ldt_key": "CCE2C3E3855D1E0B5196B009D8AA7E9A33D9BA36AC8A0F0BC4F9D4417FEA6F4782EE02DB8856276A3D26B17DE25A56DB0F39B34A62789801BD720A64A97E731D", - "hmac_key": "BAF408EA5111A8BF7022076F0C6A3FEEB11B88F7E106AD332F32A0395AA543F2", - "adv_salt": "2287", - "plaintext": "D0DFC032AE3A31B1658EB392B58A721CCC574A0DDE", - "ciphertext": "D30E3212FD8BB0092EC05F5401685650A874AFB2EB", - "metadata_key_hmac": "692398735A6A56DB92FE8A2DE308AA467B96B37F88E746C3DAB2E2ADD06EEFD1" + "adv_salt": "5F05", + "ciphertext": "D1144B782E41E9310836AD8FF4ADCDBAF4D50AFB20398880BFE01F40E6435D", + "hmac_key": "C3FDE0D1EE5DB2A4C4097C61212C85582F00A30066E8E8B2C189BC12AC313EB4", + "identity_token_hmac": "57A56DD881C931DFEF3A0CEFBD018DAE449BEBF6102F49CBFEDFEA4F349C89BD", + "key_seed": "6AE0CCD8C88341021FCA2AFAB8CF9A26F8213761C33AC1AA792C37DFE8DE23D1", + "ldt_key": "5ACC33C3EE28218743E13C94FF17580DF5373C66B31F058AA1891D0279B29248963CBB61908DD3837DA8A969354AF6FAAB90198CA8E9C25F99AFCC3F4E09F7B9", + "plaintext": "EF1667FA173964C2409BBEF9575B14BE42E55EE97E918B8C727296C3549C60" }, { - "key_seed": "F9487077F24434B11148BB8DA3B2658108D2BF222ED246D527E40FB79B59FA65", - "ldt_key": "282CDF83E5EE41D0949197EBBAAD19B28F02FE6F44DA2FB9FEC35EA40F2348C7E95FBE9380BD8F77695BBD471A97FDE3450372654EA78542A3663380E8298EF8", - "hmac_key": "8EEC4840DE8DE0B81EDD07F9EE511117CD9A43CFE257FC01040D6DAF011F719E", - "adv_salt": "A067", - "plaintext": "7B9C8E0DAC001EB757759681787F4C0A1CB2B7030D", - "ciphertext": "50F99FBA92FA54662392A5AE8D2F1358F1190C4EA1", - "metadata_key_hmac": "35B5BBE5DA396CA036E210BEB2E03C9E7264EE17CDCB67160C90437055C61E8B" + "adv_salt": "E50C", + "ciphertext": "04DF1A3FFA9E13D0AE1247212515D2C874A3BB1B8FE95C9F", + "hmac_key": "35BFB86404B08157E7F7EA6AE76554F3B0D3E3729E76D239EF1D07C05B1C7751", + "identity_token_hmac": "42DF5349261E6B238DB891D50ACC180CD9B29D925644CC4DE2A6C04192A2475E", + "key_seed": "A457F41ED883C88BA95D1E5E7DD69BC4D7D809793F9662944F7CE53993BFC62D", + "ldt_key": "0C3FC621712AAE7F53A36882BBA9BBE89B593751F357441E1EF2A41ADED4D3C86CB4CD9A495EAA6889C6EEBE7D8301C04A1B079FC6C511DA8A4690638B8F2694", + "plaintext": "2C4AFBCAA759A02727DC48C8073F99E3B0F8E19675938653" }, { - "key_seed": "94279528D378F37D783AA85DB718DA2941239400BE724FCC51DA86EFD6521446", - "ldt_key": "2CE2FA8D246C4B62057946F530FE68849CC4FBE0CCE24735AB40A48745B6C70525B09EED434E4D474DB9017C9CA2D96212D1E7D2944B2EA268AFBD3C1DBFF81C", - "hmac_key": "AB0C8B4EE4FC540883CD901E962208C3A679A4CDA121E3C3E47AC16A62C26552", - "adv_salt": "FA74", - "plaintext": "9D179C9EB9231E83D4902F87AFEAA97FFC82A8557D", - "ciphertext": "50AED9A942CE93D8A1EAFF67F166E0587D64F030CD", - "metadata_key_hmac": "777C2293B15142B27C7BB06C22B04CA63E98C4B7DB346D47A09D3EFDE8D57514" + "adv_salt": "369F", + "ciphertext": "D57B58FDE1F1A9FAA283F0F667EE82EC38C7FA83D2B5D58758570B85C03C25", + "hmac_key": "C07B61EB61B1E39F831A27481E05A45F646910DD10BFA3B9D4A9F2246C87C7CA", + "identity_token_hmac": "DC969C3953FBAE39F574ACE5D32636648454411B013A4D3F15F6CC03D6503116", + "key_seed": "0B70FAFE46D165C61580477BF0F8E95942E0D1313EF6DD38531256D331BA8EFC", + "ldt_key": "FAE613854ED28C718764B2DECA45FFB038D12ED0B8F4CF8E410CF664135CB9AB3F928CEC5ED9AF6EF05F4BC8A5B802112898DF299C8EE6D7B53364207FDCF802", + "plaintext": "BCAC01D17493B2EA537BD4D0F9E6A81A3C5FF21E2A9CEEA2B5A39066396600" }, { - "key_seed": "C0A10BC69806D2FF28B5159E2F3F969A2B36F82E3D55DD99228517346A2C1984", - "ldt_key": "CA9710D1304CBD14C7D22F410443386DDF2583A20797D8BDC5A5713A47F6061C674F3E13CAB597A682DA56469EDDECE75DCFF1526F63235620F93A876F5977F4", - "hmac_key": "892C75A44BE2A7C54B36691D5ADBD115F0E1A6B020873896040A8B37E59C7EF0", - "adv_salt": "E15A", - "plaintext": "7B896CC8905C681DC6B1D687739184EAAD5C66C32BF17DE37E968DF5430B", - "ciphertext": "B10E441FD7D946E45E10E96F418B38D5EAD75409720F61E74B33BD7FBEB1", - "metadata_key_hmac": "9D1A04D804D3DFFE0F18C5AFE025097B72F24175EECF1FF4D32A9A0332A33CE1" + "adv_salt": "4270", + "ciphertext": "77E4E229422367E0E3C29826F7E586DE3813C9F22D41", + "hmac_key": "CBC601994BBFC3A47C23F03A6F55B265C76BF5B3D4DED01C7AB3417BEB970321", + "identity_token_hmac": "E1B64D12ED7836E3303F99A545F33DBDA58E3357AC39C5AE0B5CB728D5585510", + "key_seed": "4C0F2CB9CEDB8BB5C6B91C0DD7F769D2C6474EF2788F45DA8EE73CE1536E5BAF", + "ldt_key": "14D27C8012A68D40CBE9C725B1B20573F8BE0CEF409826236150505884B27D0DF25356EB0CA8E9E6A6247F563B4950BF76F59A491A56F76784C041C49D338C95", + "plaintext": "88189E5EEF3ED4711CAE61B36CD3C544997F28FA46AA" }, { - "key_seed": "DC3CA750BA956949AC3389B896359142B0FC41CA5259676A4D974B627F355674", - "ldt_key": "884D16B4BFBDDD846857C57B5CD1912207788A1B3F95D5AA7218CB4AA3E21AB4D0C9518E3DBF09CD2C1A31DAE2DBF04E96840E81D8FD9166061B1F761834E270", - "hmac_key": "6437801B615156A92363D1D70CC37D8DBD1D5122F09AA4775C99402B29D97794", - "adv_salt": "2A38", - "plaintext": "565374DC1B36E89EDD90AE5CD77F9109819053615F590990D203", - "ciphertext": "EFA8C9D21EF4E65EB7D398EAF277EDE24F9D3D4D4CCC3DEADD4C", - "metadata_key_hmac": "CEC61A875AEDA4C3E1F4BEA7F5D5F48842C9677BFDFD3777ECB6998F412623E1" + "adv_salt": "0784", + "ciphertext": "8D5E6C77684770924C1A4A491ED92E63EA149226865EF70260", + "hmac_key": "209530DF75729473CD56AE03E754CA630B979A9232BADFE403B87D4271BBB80E", + "identity_token_hmac": "9BBE2CDD6C7318E218D6E9C7BCC7DB547EFCC275440A2BB7CCE82BACD6D777EE", + "key_seed": "C5E3CF6049EBD3BDFA10743AEE32537C75BC8D973C808FF955AD0EE4066E36C7", + "ldt_key": "AC229422EFF9F36205FB996C070D3115319F2A94A4C01A0DEB1094D3C56AF7092EA77EA7F8FDF879B22A42A9862610724AA8CF1FFFDDD7809513559534EB70D5", + "plaintext": "DD3E6E54270CD303B0DF06A5777D3AA7A82A855112A2925001" }, { - "key_seed": "1C3B8C1D9EADA715EA9E9D0309204228015824BAA74D90880AB61C110D17B275", - "ldt_key": "6744922661B4330F6E0FFDE562D5CF4FB2D9A838E6FE17226FB9AD6DCDBD78BDACC587389421144AD105DAD1C5D5B2C0637A380C81A6AECCD5521D29A0E103F9", - "hmac_key": "7D4C0C0252D8010FDD7F1D4B77DA012C9F3A8CAB84D2736618F7F0991316BBA4", - "adv_salt": "8E40", - "plaintext": "9989667868EEF966DE52DAA83A79F442257CBF18D27769F2FAF5BDF6B785", - "ciphertext": "21A369488B4FAE255E9EC83844DAB5FCF3657BA593715570C010E1B3977B", - "metadata_key_hmac": "53E639D5AB5948942DD6D9946F95A1A6EBB9B93A186E50E918E0609B8E3DA45F" + "adv_salt": "FE5C", + "ciphertext": "A1C75E7100B6E524141E97A24DBB7071", + "hmac_key": "FD0776C73BC6A5B79D3E3FBFD04C7C9E3E137D82E9F5F426B2CDE832BC7DD6FD", + "identity_token_hmac": "A1C8176B483F1D6DBECBA76AF08D7E62972F98B78D0712B9AB1298BB08B890D5", + "key_seed": "1FA8E31F66CEFA5302493A7413EAF5A813ABD73BAB089BCC2E2B25DD5320F8B1", + "ldt_key": "862229764161E53FA6D8CF8CC6A3D56DCEF546483118DDDDB10A6C22287645B0375799197C9DC42DB8D7A96FBBA551B3F4BD28F908C8EAA7F177EFFA28D4BE59", + "plaintext": "AEDE409688E9631E14C183F57789AADE" }, { - "key_seed": "9829D6447C561A4BA0A5EC0E0C9CAC8E5DA6430FE27DB0D0E1D751FFA5D31F48", - "ldt_key": "428CCDABE1FEC7368F57CD23F949E8146871678DC0A18F7566E29A07014D90524BB819332141592B70EE68833175CE000C9D63EFAC241B15720B4D19E0607C5D", - "hmac_key": "F47C1E3EEB9A14EF81797EC8FC3A5BE1D886A5F25386AD8B7413205273CCBBEC", - "adv_salt": "440F", - "plaintext": "920B77B8367C89A08EC9BD91DAE8F57E808A8D8570EFB5DE56F7BA33A75A6B", - "ciphertext": "6DE0BADF95B7EE68AADE0ABDAD0EF726C1584A80FC2A7965BEA2CA481D6A4E", - "metadata_key_hmac": "EFB87B5515B40D8717C7617C2033F9150B41C29BAFE50A69BF0A2C95DE5B19C0" + "adv_salt": "1E23", + "ciphertext": "D3015A7E2D2486B1D7F07E17F68C5E43A377", + "hmac_key": "248F166010A6A85ECCEDCCEC056D32104A7882D0BB0036ED5D5011D2A1BC9C6A", + "identity_token_hmac": "0D3B2CD8E7706A893755D6749924AD5CA2F755B427CA8D51786D578B0BF11F54", + "key_seed": "DB335588CBA2795FCB41A6568A4D38945E07892BBFA462FE7016D3CA1DFA8E78", + "ldt_key": "9EC0F76BD542B03159B10EB6F375D8F02C93D1243F434E4356A4D52714D42A6E7AFCF2C63D462FB2C45256E696F5DADD5AF5C8CFFFD6B2BB7D758EFFD8B82247", + "plaintext": "9FEF46046655876C4A397550BA23C069C869" }, { - "key_seed": "E87CE30B3E8CA4FCCBD01458EB57F0A54E5F0A1F013F2377461AAACA9113A715", - "ldt_key": "207F249256B15A443DC418BE6CFD316529266F030513B25DC88D7E86141543E0639A9F1480C320E565DC0C04DF83CBF630A418A79847B7FC56D2E68E0545A557", - "hmac_key": "7BA64235DFADA23F35D3BE3CBF100A6B4BCDFEEE28BA79CF914400E1FBF5CECB", - "adv_salt": "BD1D", - "plaintext": "3E72346BB0A79E75F6DCB30AD5CDB27758BE405D615F7CD931CF468F01A6AC", - "ciphertext": "D9DE8FB0D2DAE8863511B3179E5CC7E11E77603AF625DE1157A492C6ED6EB9", - "metadata_key_hmac": "47E0AC2BCC093E9DD4D617D6D12697A7A8E6EF7EA3153C85D6E6F8B1F5CDB73A" + "adv_salt": "F60F", + "ciphertext": "72D6B0C1EF949E0C6AA41084D952AE49ECF7625E8ABA6C", + "hmac_key": "3F666E45E16F4208066365B7BE13BF730B5432297816FACBF4F0F42D68B7B330", + "identity_token_hmac": "44FCB520188601A392A46E78B799EED60232D4C34A60FEC15A4631FD19B819B0", + "key_seed": "34BC6654E79D5DFB031101C6B9A0530A66522BB053318F1A890E7659AF457FF6", + "ldt_key": "BA0872DBF9B506C80911EF96AC938DD5FC2556048DD8A0A6E09D1B16B1FE89948D892DAEF7ECF438F24020AD19043330CF88E9F951260D2764875C0D8CFA30FD", + "plaintext": "2671280D380269EFA4AFAB7F8AEFBEA3BAA546A693226F" }, { - "key_seed": "0263E7AF4055525AE31D64FADFF6CC1295A8034432020528BE6E56D69CC2B681", - "ldt_key": "A8BB317A8086B5DEC813237497EC12C897D1621E8D60C22D015F2E2AABDFB504122D22843E26F4B2E9FB3E4D0A491473D13D7CFD604B9D51A6E06452FADD3E3E", - "hmac_key": "A65B8453EAF6B2783E3AF93D3102F4FA8CB2BA378482E83F38182FD064D007C3", - "adv_salt": "A10F", - "plaintext": "0EBC9C6404682C8BD3E9AD99A1A3D7618CAB6114FFF6C875958049C1C5", - "ciphertext": "8E75136143E94C631C2944DD32EBB9F0696F346EBB8D7444686BAF02C8", - "metadata_key_hmac": "AA9F58AC9FFD706330B4EC958F101DB57D46BD88AB2DD265F70F5250D9915A55" + "adv_salt": "6245", + "ciphertext": "1FB17D4DB41ED8A69423D1D00E70F1468A6282C4E46EFBED76", + "hmac_key": "842A046AA27B15941FBFC1ABA675D054ED43AE4A774A621C0D79E669BCD759E7", + "identity_token_hmac": "301488269C15C06DD58C63D9F32F3EF5F1F25FD5824F5BBE3A075A0294E2DE8B", + "key_seed": "7784295CB941C0EA8CE99F532BC4356BBB70D6ECBF7AC8AEA9092111D04D769D", + "ldt_key": "86D6FB6D2D96A3B0EC141A3D6A97B7F40DB56E2C068B735ECBD106E34335DDDB350CE5EFBBD76DDE01BD4C5BC8CF5AABC1C2144793C9F30417D59D3CDE0C7B77", + "plaintext": "8F1813881C5F60FD25124FE0EE83C7585D64B028989FEB6C71" }, { - "key_seed": "7876C9FB9FB4F58A761A7C6CC0B04368C93DD0E955AFF705C013D59AC5051896", - "ldt_key": "A300A6502E3001A500382DB2A10FA6B8C8C8CE2CC52CC75573E140B45FF7070C17CCFDD48BFEE0E72E18E41A46C242514620462E9A9860ACF1B22C16A4C2A125", - "hmac_key": "58559479522C1832647EA8F24714DF9D91FBBC27706E50BCD2888D8A36F46325", - "adv_salt": "DD6D", - "plaintext": "A4719D72E2EDF46B58D89ED9E8083306F5411AD487AFF4ABFCED8947", - "ciphertext": "8C61A76BBB3C1632037E5F20924BFD1801801C917741AC2A59DC16FD", - "metadata_key_hmac": "0F395A1B09F0A4F5060FB521B9EF59796339A9C8B70429960676748E07A777EC" + "adv_salt": "0647", + "ciphertext": "D1DC1D59D804C6F1066A153C50E6422A1F2A7FBD178DF7FC68DD2A80660905", + "hmac_key": "07BA5F868765444FF645C2975B1FB48C940C7372BDFBAC405E567C90165E8210", + "identity_token_hmac": "CEEB6515F58C53E6DF672636B05AB55429B8AE86224F66C8A812CADBB3B98277", + "key_seed": "D52DA32B6F65746B70EF2E6F99935D94DD3D60C34F1A7B5876BF829E5C67982A", + "ldt_key": "5BCD26A319297E8C1456DA63E5B88650905E2829238078D6D7350B5A6F4F955389C62DA84D47152845FE19BF4FF79EE81326833C8AFBED1CF2ABDADB5493804D", + "plaintext": "B4AB4964CC3C08873D0EBC40C929A6E4D0D52A0B3FDC70D4F93D1432DF2D46" }, { - "key_seed": "6FA2BC03F573158EABAB35B48390E46B1D4070C09E0B3EB762878E8DEBB5FC07", - "ldt_key": "9BD667DAB846D7A2DBFCECA1ADAD48A933A7C75256B71221925C7B14EC127BBF82F4EED25B83589447F3685A6A2D862504AEEFF120D4B20D2538E5A03909103A", - "hmac_key": "ABA1A56B7051C0344F2BC497B5AB2A1D7037D7040C821C13428569A3D1BD6FFB", - "adv_salt": "B9D6", - "plaintext": "9FB0C213C041D1D1E134EC482C0CCC80FC", - "ciphertext": "C8D19DFE4F8C99D1026AA6E3BECE8A82E0", - "metadata_key_hmac": "E8593E0D4C29738FF3752BC5E905AC21DA793328DB599552BD86B71334E92C58" + "adv_salt": "7560", + "ciphertext": "896F81B391D7D6722D9C3F13BA3C087543BDDF119DC6", + "hmac_key": "E517606145DDE8EB4DEEC1F3565AB4E85C7E1D843FE1ED24F54D4C582E85545E", + "identity_token_hmac": "89A947F96286E8EDE8FFBCAA51CE708C06F712E09A8EBEF024E1905F07F42058", + "key_seed": "5EFF0828AC1743AB1F473CA562FC647B9A95558E737E8E2FDBC3E05C15BE441E", + "ldt_key": "BE3BE0C9A041845831A8AE86DC23F8F8EFC935FE231D7D812AEAA1EF47D59AED776C8DD7080F9FBD00DF74D5D9A4C1FDA8ED1F141DFA1A2CEC01CD09FBF50805", + "plaintext": "A73CDA171E2ECCDFBD71C5B2BBBFA33380A79F91F5BC" }, { - "key_seed": "A55A9CEC40E1E37FE8BFF5ADFF4C68034F4589064D530388005F97715011AE02", - "ldt_key": "75797008482530202CF7BD71CDB51A9CFE2D505A393FF9A0849178239EA6E739FFE58B8153EA5749B6B53F37C1E6BFEE930E5BCD97C9E470DCC6EAE6D3417A07", - "hmac_key": "3C6162C6EFCA96689B94E84F714C8A00D99789DF7D3FB8E06774C39C73BFEB7B", - "adv_salt": "5EFB", - "plaintext": "9A05585013112CBCB6716344AF4CF92C3764CEE150430C4A8B72B1B0303A0E", - "ciphertext": "D9814AB92D016981018F136C02107D819A27F3A2C0A2768D4AC36EADD7D672", - "metadata_key_hmac": "AC1982323640547F148E7ADFF917DD087FB98AFD3C3139645A2A9620907D00F1" + "adv_salt": "7CC3", + "ciphertext": "047C631815B607C024C28D89330ED7CA7C34A1F84D89A1F0", + "hmac_key": "54016DC977C59CDA4DB4386813221AB2A2461E27F762C9EBB414C5ED54699820", + "identity_token_hmac": "2E5F828069877C3C7D35754A773EF067AD4ACF6DC0C6F1EA38C981459172993F", + "key_seed": "09078590C19AE6B515DAD5F2739D35BBCE6BDFDAF3BC348C9E54D8DAC8131B28", + "ldt_key": "34D97B145B530111A67723BA9CD3ADF0A588B83952186868EE050758D29F8D486A2364FDF5939D0C9B1418507A68AA52FAEFA20C7EF288435429C638F477BAF0", + "plaintext": "020F95368483CBF3BC0868E3CC6E0439B117323016414726" }, { - "key_seed": "5BB19F6715A9BF3C1572107C27104BBC0E6D6AC4F984BD4B96931F79E6C585CE", - "ldt_key": "626DD569F79E1B91B42ABBB45C4686895563370718BAE54A6955FFB4FF9A93058183CDDA102A870C2FD53B0CB0172D46BC037B3579FBFBA603639B705383BE0F", - "hmac_key": "5F4B431121110ECB86B89EE8FEF343E07E4BAE63452320375C13109CEDD98EB2", - "adv_salt": "6DDF", - "plaintext": "7FEAD68893990AF7CCA7E26E94D0B1FBFBE58BF130", - "ciphertext": "EF57EDBE41E2AEDA8F8CB43DCEFD5B6367BA5E8B92", - "metadata_key_hmac": "BEB64F4417ED86EE5C150BD546970894AE6C7F48F931CB980D454E91F5ACBC38" + "adv_salt": "2A62", + "ciphertext": "6260B62E7005E2BA06B5FB3FAF71920EB5A3A579E3D1", + "hmac_key": "2CC37F55F21309A6CF34822F88A121989182274CA8F5CE4DCB462DA1B40433DB", + "identity_token_hmac": "7E095BB480D774682CB8E4729D69713685FB39C907A0806D448C61D1F779A9FC", + "key_seed": "8786BE0DA0D4484ACA7EF0E0045B376C411AEC27B813EEA3A2B7596F46179433", + "ldt_key": "E7965F807E1D7E93863736102985B943A5C88621B560550C5288B28BCAAE6BC223B69EF2CAD44BDC5C2677F901F2169CD9E62850EC690DC86040925F4E2F9420", + "plaintext": "6F4AFB850CABEBA63777AE6424EB517E04D494CF3ADA" }, { - "key_seed": "A6663A8EEE1EF41B70E814267C9F2603C8B557AC51DA181A69C9EEDFC5F19528", - "ldt_key": "DD58948746753E17912CFAD8BD69DC9ACAF20119AE60BC41AE2A6A1C4CA53B33F65922EB92C116E25D27B6B377BF4635C907106418291023444B0582B622C5A2", - "hmac_key": "1625F8FF5C659C118993078C731330521D63785B51E5C0A2A0BFF8DA6F3E69B1", - "adv_salt": "810F", - "plaintext": "1F326F6587D80675DBCE9E0C56F2E95663518BEE5E", - "ciphertext": "251F2687ADBFDE3F4163ECCDE0380D7746538155F7", - "metadata_key_hmac": "E6AE6DBEA57A83A5AF7A2E7AFE745D477CC39C10264B0B30F29CA846E6128E4A" + "adv_salt": "C856", + "ciphertext": "CF420AF892CC3B42ADD3577D350209CD538F2224302AD46ED89272", + "hmac_key": "C00EA1BFEAD49726A4B4C56CFBF219BD0E37295F4C1C838EC473DECC732F753C", + "identity_token_hmac": "F1A9C559BD880189641845E9A651884C590AC1CC4165DECA33AB64C51F2689E3", + "key_seed": "5D4FB15064519023C6218E35AE9B2D52D342E1E4310BC876A282E4078DE3B3D1", + "ldt_key": "BEDCA450ABCB8B5103A7DB0F0528A6730562B0934F62DFDFEB8949354D0CAFD4E101AF5F1ABFC20E64B979C3CB4D73E69190A41E6FB135DA8FD05D0631003882", + "plaintext": "249630967EA149B9B2F2498B9824A52D317F1CFDBD16B2EE0C830C" }, { - "key_seed": "00828953A1AE0076B75DA512511FB1A429C25A0F1ABA6153368267A44FE960B2", - "ldt_key": "71F2A112C0956E80955B3577E51D44C41B1AEDFA74745AE617326FD6FD826985CC466AA4249AAA64AA122C4D5AF7129411358876971D31F875F969925529167E", - "hmac_key": "5BD823CFAD624CC841C0C714E08F1A919F846E0FCB8B125FD08761825D9087F8", - "adv_salt": "181A", - "plaintext": "9C048A6138808DDA7B467085DA77FA1ACFD07A3544DE", - "ciphertext": "AA663B104A0B7159D99C7C1576499B2A23FDA7A567E6", - "metadata_key_hmac": "37EC37D5308D056454955C51B93E4150F2C56416EA7C6C948B9076F3C573A187" + "adv_salt": "9020", + "ciphertext": "DB1FA74871692FB6FC716584821A0CAC608E", + "hmac_key": "F5282F1B47045F1503FA6F0BB6826C9CB4A5C3C2D96F4CAD328D91A0FA60DF5E", + "identity_token_hmac": "E011BCAECDBBCD331816032F019F76078C1E47806A38DD6A2928231C9C22960E", + "key_seed": "16042559E2AB7392A3C297B88FD0A3694D4FAC223086B03B60473DE84B3A4B98", + "ldt_key": "134CEFEE472C4CD6066D064A6DD705D21C1FAB43174B096063C8698D4878F9F356B15BB6B695AED38CCF7A54B132B47ECB9B429F6CC12376B16CD285F25883E4", + "plaintext": "3801AFDDFD22B16A9FC330A4D14C0C216D9A" }, { - "key_seed": "D660CEB399C3E0E51F3C491444FF6516D5BE55D6EDF620998B7D30ED0E80A7BA", - "ldt_key": "2FDB0A3BAF8990143F8D70F648C4727675C5BF066DF7757FD6AC0F2D4A7BF3A3A10ECF1B66264CAA29F0FFAE99048FF0FA7A646E78B1EB78C5C1F2D4DE6AF2CB", - "hmac_key": "A5FD3131713A68D6BB887EBCF083ED873373959807431425A388F3AB8239B141", - "adv_salt": "FEB7", - "plaintext": "EA7CB59D1E9F4203E2539E950D60EE1DB77861FB", - "ciphertext": "486BB7E2D495B8A5980D0A4E1C9CC9D9B3F23F55", - "metadata_key_hmac": "0789ED2ABA65D4552A7CB7B9A9959E825F82FE5D9DE7AB9514655DF3AC873F11" + "adv_salt": "B416", + "ciphertext": "3FD2CA364E9ABBA987AAE45D5C022B4AF774F2", + "hmac_key": "0C4037B37F9C4D607D91304CFD787CCB548720965CD5FCCC9CF7D8F1B4EB9EDD", + "identity_token_hmac": "1CDEC3C91FE18DE6E6B6022DF8C095F0AC05DC94168D22E86B83DDDB59EEB5AA", + "key_seed": "DA40AC0B2424FA5F53FC032ECDFA9ABD8435B908DFE451A3943718A68FB1B900", + "ldt_key": "7706D3DB253174C1CD4AF31690B3F5BBB4723CE48DB1685812481FF083FB7522C8049855F9278E73BA19A670C1E6834341250D45B10AE3C0995AFF261EB7011D", + "plaintext": "7709999026D4CFCB96C8B51A18285F00AB0609" }, { - "key_seed": "4312F7F5892996C4CA4342A3309FCD0EA601AE94845FE91DFF56A95385F3C60F", - "ldt_key": "B8BA8FC9BB5F78EA07F0FB9FDF9FB8842FF334AD67AB8EACAFD415A4F6E085D5D7518A7AFEBB6E5423D62986FB039AE8FD792A8E285F952E4A7FFEAF7D134EC9", - "hmac_key": "18D8409206BC997C599263D62CD44380B44BBE22004E510E2B29B06C6AA9A506", - "adv_salt": "0FAE", - "plaintext": "74148EAF740DD87A25DFF9285D1FBFDB19F3F950547A1E453949F6A2D8", - "ciphertext": "AC7873262675D66AED37E19730DDC2B36DF22A68CD8B1E1F08E6B3BD30", - "metadata_key_hmac": "3BC5EA33917B1A9B4FEACF43AED93705A47F96016DDF7DC4AC8707ED10B8433C" + "adv_salt": "513F", + "ciphertext": "4C356FB91804FDFE40D608D2FA95204F", + "hmac_key": "14E2A8EE9F3439A5AD0D91AD6659F861763A5EAEEA9BC9FF950DD550EA5E2144", + "identity_token_hmac": "9ACC36A7C4AFA0D810E51768DB0D1280D3E7CE394C7B3CACA544D86D7ADBE685", + "key_seed": "AD90C78112CC93EF1D588CEC6114ECA8F949106D7498B6FF2738F60D4C39E3B0", + "ldt_key": "4082257057BF11A9A8EF7EF91862E420957C86ABC1DBAEE5FBABC3833001CE0B90D2096AD4E44B16C3F76DDEBC0FCF2C9E320039BB528ADA89AB806C5EA47FF5", + "plaintext": "486BBB7782B4C679B59D8791D1982985" }, { - "key_seed": "60936E83FEB011BBDDE2C861564F8B349DEFEAF325FFD852DA601D5521830C1C", - "ldt_key": "B6C7D5FBF879C182B491B13BEA3760A246A7D49052EDB4AA0B22E099706FC11F5A5D70679617F1B56647B1B5EFA7544973CD60A5007CE966BCDFF8873EE10C65", - "hmac_key": "3708BF9E9C2EA13AE58F00102B2744794614687B50D08560E22A09427E26EBAA", - "adv_salt": "0749", - "plaintext": "D647802D5DC37E30A795DF344746F51B5EF7E94549", - "ciphertext": "9C8E99384E6926877C9F02B22A2BCD219EBC68BA6A", - "metadata_key_hmac": "1E510537E57C913E1D20C57C8D21AFB54D5ACC9839D66B398C9ED2DAC72B6BA8" + "adv_salt": "BF51", + "ciphertext": "FA4F4B54B39030D78185D71ADF35B70CDA4A67FC61FA30118DE4", + "hmac_key": "5FE98DB4539BA363111EC9E63F36ECF1E712B5EEC6C1555E75F47F34A66D385F", + "identity_token_hmac": "93202A0D36100FF814B3B120FC185C84EAC4AA81CE5EA1A17D2D73650B6B502E", + "key_seed": "2E0266AA823838A0C03D3FB4AD0A51F425379379067D7A0CD1650A1BFB2296DE", + "ldt_key": "58618E080BCAA76BB5A446A81F26C902F9BA6246C1C9D01F5FF563386BB143CE1896D9CB3C37A369896C12D8088488A3EC82369EF659294E62F69046CC82C8E6", + "plaintext": "74F37042ADA22F88D0D338DC74409A3E80E676BF0043C850C404" }, { - "key_seed": "AC3CD644EA7AFE34435A1F11546FEF56365C4BCC580F95447E03D5FE12AE230F", - "ldt_key": "6EC72CB753BCA51C05D3A6B4EDF1B34E531E0932565AA7B771C79240759F4BD0EA290CD8DD1C6EFC07A3F8113F4F58EB6A00979F8D3B7B855D9B665338F3ECE0", - "hmac_key": "5971FC82754E0EE3CF5A79D67535F9B6CA5DB532471F30D01CAE7484DB8EB33B", - "adv_salt": "4558", - "plaintext": "5C0343A00C399C9862B55BABF4C5D94CDF243989433B0E", - "ciphertext": "CA47DC24D0D1E4F976C5A58074DD1D9FA218E487113DE0", - "metadata_key_hmac": "A1A0FB564882EDA231E4CBB9AF4F12E674CA51ED56CE5C251933AD3BE39BEA2B" + "adv_salt": "D0FA", + "ciphertext": "89E8307036BE9F3443FD98A08B163015577770", + "hmac_key": "58432E0BDDB8747F3EDC68085087DA99E4F14798FC9F10B9ECDA092C8B00C7F2", + "identity_token_hmac": "726FFA6370BCC23E1DD2B80749CF9B5AC77668D189C46BC09086DDBE16F6B5BE", + "key_seed": "FA95613BC2BDC64E9C2D82C588162E1820BDB21BAF633D6FDC910FD281A53433", + "ldt_key": "FDCD5116C85434334874C24E5583304A5DD0ED401E9ACD37C2F67E61CA108D85389D37A59164AD103698855FBE92FE2C1BA44D9C7927B6463A4119C4113C24FB", + "plaintext": "F5B63533E7C12F59B7C7328B91771F20603B17" }, { - "key_seed": "901A6F048DF80F4D09E6D15E793846E86A62529A17990A9A76AC394C2949FCC5", - "ldt_key": "5CC9EC33625EE5283826BE48DD42DA644F4224411E31E71A834CB241C8D56C442D119310956B7C096E6BAA30E1891E199C06D8767AC2D4C5B5D6B7B4BA096975", - "hmac_key": "0337A6DCB3FC021EFA02EDA3ED5399B3627771194F77D6F21E5C78D234E54221", - "adv_salt": "A8B2", - "plaintext": "1646727763D58BE646D4070BC80C4E5FBF1B067691A5D21229", - "ciphertext": "59E2B0C2BB88D5EEAD5A8F733F2DFF166556C36A115254841F", - "metadata_key_hmac": "301C5DEEBA0A29EE04DB005A0831D0CFE83B102DBCDB7323615E0CD986B4F735" + "adv_salt": "CF97", + "ciphertext": "8E61F3D054491EEDC16B5D1D41E6AA288DDE01EA85949CAF", + "hmac_key": "F4F2F4D0CD50C49DA9C53544C4A55E28076F32042F47EE683E819D88D485B2A8", + "identity_token_hmac": "C45FDE6D91388B9C50CC240AF29105B8FCEE1AE8DA78279A44CCA55D942267E1", + "key_seed": "8C055A0D0A65E9E916540B1A644402C49BB52A8640AA754289DE2DE277D0A8F8", + "ldt_key": "6A9BDFCDA9110ABC983DF3439B4D1D01FC85065BBBF29B0D7B8AFDC533D38A2CFE97C2A9E68ECCD5CF4A69ED2CDF4B8B6D832E382AB9BF6DCEA17CF16717162F", + "plaintext": "96AFDA3D88FE3DB2E3DE4DF332146F867BE90D9C43D2C47B" }, { - "key_seed": "7FD07DD39B68FA5AC3B28290D300A2796061CEC41885AEF1605D3C420F4BE7DD", - "ldt_key": "CFF848B80B0E57D8B2A692AF7E8876CDA6F720E4E52566A4422C3F002835F0DA2B76813CCC068504CC78FB07BFBA602454146F2D76BD3EA439305FF2B7E5249C", - "hmac_key": "EC4070A926535FF84E397CD857DDA2AB8F5413DBF9F78078CCAA44EFDFA8449B", - "adv_salt": "EBCC", - "plaintext": "6C1E0BC720D2B60D5950D4F83FCD0AB3AA52CB", - "ciphertext": "2BD9294E740B0E86C0BB41A806A04A549903B2", - "metadata_key_hmac": "5EAC027DA7F61F2BC016C0F4B186DF3F036063DCF44EAD4527A05EB58D7309C8" + "adv_salt": "AC35", + "ciphertext": "3E928D6767AA90A759784D4D13FA6EE2EEAE2A35C4DCF0072E3A09D4F8", + "hmac_key": "DCD67593752AB14E87BB808300C6C66C91CB2FA25D62A6514F556564B331BED5", + "identity_token_hmac": "171F0532504142E41460159A7D1837DF2F850858DDCBC951EEDA65AC75C32A7F", + "key_seed": "882F96B6ADDB9D6FAB79F4E60C643AF05AD71F3B24E4ADB3CCB7161479BB0EE1", + "ldt_key": "31EA954EC47F5FDEE4D3938671AF77521788E73E090A6F2A66B67141055CD75DD33F4B8E42163B2F21C413ACAA498F03B74B936195D13042B76557C232960F22", + "plaintext": "CF7080DE671FF22EBF40D640BB936F353E82690498EA296F41F94D5C43" }, { - "key_seed": "C68092CCC57F93CE005FFF8EF45F5B880F58836E6CE859FDE3E21811587541F4", - "ldt_key": "710B9E649C1594026187E19EADB0AA6879F7F8C0CD2C447C95143EF0F215B74F39DD092D87FAA0956A38028A6B1EB487209947F6ED26581B8770BD61FF41F313", - "hmac_key": "9DE1EA3B995E7372264FC4403F500FB1109F1E5E04611C22A2AB66012D04938D", - "adv_salt": "A212", - "plaintext": "C4FFCE44E03DFAB9C6E872306336F45D392B56890404FB", - "ciphertext": "FB89DCC92612421F8E738F6842757207D0D9B4F4A6C945", - "metadata_key_hmac": "16E4235205524E457427C43F40D1BB19DFD5AC2A5F8F0832E9F299AA1167430C" + "adv_salt": "B613", + "ciphertext": "CB3041FD5DA18A96FC80C8B1CEF3550B978C70DE98828C2B8386DB", + "hmac_key": "C80FB73025F878C94D9B1D0FBFBB0BCC2EC58E6B70CEDB0B6F5C8CAFC8B602A3", + "identity_token_hmac": "5401E6D4577B19A6EE3BE303522F6BCC479C3EF6ACC56D38A92BEDDB52939B6F", + "key_seed": "7DC4F44DE1798BE251D7E7A04C1DF966F9AB95F9FC5A49082748BA447DD15FBC", + "ldt_key": "440AB453063146EEC285BA78D07FDAFB4A16BB8B7B53BC280BC4E68CD941393049BD2A3CEE1E5BE355F45C0C6409EB1521D28C8E349D30F5C1B3288109BE10FE", + "plaintext": "AE6591893D5C744DA7994DF7739188EBEEFD817D1952236FE69AFE" }, { - "key_seed": "15DDA0D93BF9B9FB9792A3916A0639E52AA8F9880CFEEE1C98F9D0C940104F61", - "ldt_key": "92F261A46A17E4A7CE4BEF7A817D79828DAB297CC5FACA83790EB864ADD70B935FFA1D2464469FD655988B0118EE931AA0FAE77F9521CC8CF35F87D87D4CCF4F", - "hmac_key": "FEE8B413DF5ABF9D109AC9CF93F842EC0739603CD1184F8805C5B488B52FCABE", - "adv_salt": "61BF", - "plaintext": "EBB8E7B325AA42A0450ED5F99A4164DEEC5A056183CD101F6A1971", - "ciphertext": "9A388163E462B8513A6CF4B333CC8F6E809B69E69C24E1075AA990", - "metadata_key_hmac": "66F0DAE501CF33F770BF920299390628952BE096C9387558A50CC0A754DE83FA" + "adv_salt": "0379", + "ciphertext": "DB996FAC1234138C23FB41992A7EF0780E206F2F92ABC2525A", + "hmac_key": "C1A05129B34CA6A1AF456D8131EAADA8C726F094900B80BF6803459BBB124695", + "identity_token_hmac": "9E03313DF9976F77780B8FA9EDA1CFE507E7D2C0CF319B4B9742A2B1AE0924A1", + "key_seed": "EB0E8902818056408E2596C714D968A023C67BD616739F144DF890D14EA219D7", + "ldt_key": "546A7DD47F7AB24A55A980576921D52FE5E70CA73C562CB8748570D572F26DD288055E938AEC8D20D1CFD9BB0BF62315996F8F8B9E85DC15A9F28DCCA26FCA1A", + "plaintext": "71AD500B84B6FF0779906ED33191567FBCCE0D96EA06861654" }, { - "key_seed": "3B085F2421533E56367A9BE398D88BE12345D3DF2BBC7A6EE9803B8D734F24C8", - "ldt_key": "8C20759E8CE3D70DC11C3B80D6CD8317ECE48F49ADF67D3D65D8413CE3A5930AEDA60A8D91757F521714D7E245406EE7D2DFB309CD20FC9ECB339B6AAF30945D", - "hmac_key": "4350D0803416BFB74F93F742066EB1EEF1ECF72D9B7FAB2C1BE8811F80843D31", - "adv_salt": "42B1", - "plaintext": "1530D76F0258302D0B6A844DCCEE6598E31801D8EF2821BA1C", - "ciphertext": "8FA43962DC2A1EF3D107134EF59373CEA2BF3CB005ABFB0E5E", - "metadata_key_hmac": "F5575D9501C401AD0A3585553BA70EBF575306BB4BE08CC12136190FC1B0AD4A" + "adv_salt": "C35E", + "ciphertext": "EE37C54F29697110BA36D71664924192A6A325538B02404D456A8D887DA2", + "hmac_key": "6133AFD1126BE85311C0727EAA7F4D9BF1876A2A10E1AFA68788887471AF1A84", + "identity_token_hmac": "32DEEDCCB7BC8E996B9EAAEAE13E0E39E6780E45AE6FCAFF86EC06A7B7C69D5A", + "key_seed": "B5669B2D04A1DF129C5F9DB6615F7C441379A0390811D18BB37BD30BB68B4EFD", + "ldt_key": "5BA46FDC79A07DAE2FC23FDE2AFE925B452BAB69D2E590D47A59C653626AFCFEF901AD0930F8C3387948323C95CB81B978F16C2F3F60A728D9900CF70039934F", + "plaintext": "559CBD79CD4C31B6A5CC4D3D717D7DB5CCBE81A64ED6EBE45B51F56DA625" }, { - "key_seed": "257947BBFC05D08F0F0FFEE03A2C2273A011A5F7EF9B9746158797420754095C", - "ldt_key": "17BD3B4365293E6061F40761C60443B80D6846CFD48820442E3A3B1ED58A9491397FE74C3379DFBB9A06BDF0BA9D95E1CF031E40F70B3EC96CFD344D7A945E29", - "hmac_key": "BA79FC2C050E725C90CAE0DBE419913AC645B87D79D9B4C3648EE306F3B2FC22", - "adv_salt": "98D8", - "plaintext": "7BD9593ADD66E8B0EB23C00ED62EB2EAC32C0D7A8803DE1D7CF9A864BD", - "ciphertext": "35D739708CAB44C53CDE37BB97F95396C5C73D7378E315FB2CB7E4D777", - "metadata_key_hmac": "3FC6C015D7154B5096FE63226A1144C929809D4F5A0D02D5017A35B8C441529C" + "adv_salt": "7748", + "ciphertext": "0C5878CFC2569F410D9778D63267A2E7BAA9D500CFDB22A88C5CA0", + "hmac_key": "3EF5244431BAB0D7C71A946E911D744A73F03A99C738F026D332D0F0F5AFC078", + "identity_token_hmac": "388B67797237FE594F5C2EFCBF455495EB12079DBFBCC5BE6433B5F7CFA352CC", + "key_seed": "DCD1C168499570924F48A270C2A124C0D6CC98C25BE10BFF9B1501AE975AABD5", + "ldt_key": "9BAFF61B1CD7F9CAD69CD0BF62F990D994B73322D6850A71976377AF8FB4AB909369FAC038B9F4EA187B71F68F5E213C0A79E43D98F0F3F896F5BF98BD1CC147", + "plaintext": "C4C5FF757AF9F00815632AAABFB61B7E040D44651CAECA132DD898" }, { - "key_seed": "5EEF0225548AB29601E1EC1C274F5E6B5B6119FDF0DC5CEC69D0DEDC02DACD24", - "ldt_key": "00243E2ED2C291E58F0242AEB46C6FE0A54B0F71444855ECA6E20F977071896501078D86A130D90D593A3F977C99F8EACFE3B4E7D4CD8E8EC410C23833078CDF", - "hmac_key": "37929743724C60521295D912605CD5C215294F4B55F9A667AED0FE22A94B44F4", - "adv_salt": "BCD3", - "plaintext": "1371B4C2F32F11B5DC9F9AC4BC41D9EB6CB821", - "ciphertext": "5C3E8770D2AB1EDE58BF72C45A63F7AE6E3006", - "metadata_key_hmac": "8D025FC2390405E609B15665E54AE5F912E699C6C14C16B49ADFA489FF78C3A7" + "adv_salt": "0072", + "ciphertext": "DCC53FF627D8610BB11C91E0B4B55EA42F3DD3A15CDC7A39D1", + "hmac_key": "76ACCBBA980D236DCC82B2722EFCCEAC1D100623F43ED538294EDC50A251DE20", + "identity_token_hmac": "C7521A6CD92D5245556D6FB7940D6EA4C55AFA6BF485E39C13CBE285B13A68F0", + "key_seed": "4BCA4BE4CD51155A91A05378B1F4A260DF52F4C97695BB9583F0A3DCDF79C5D0", + "ldt_key": "55292E8A6D7DB367CCD8F1C70CB5E45DAD137B88B885D3E16DA8C1267ED79AE5AFABDF8A95C6B919BCFF06A1D53D7E8BABD2C5190DF0379775D503FBFE65504D", + "plaintext": "0F3CC471872DD0DB7ECCB49FC121F6B82F580CF8A056B38B91" }, { - "key_seed": "4DBE9FAB35FB53FCF1B799B62FEA1FEB808A88C40ECFF20065A90F0F603236E7", - "ldt_key": "C2E3CF1D90B60532AEE73CE8AB1B37DA4D290E74A2AB309D3D93394945EAA28924D2CC1786D75A9AE0FA260D23EFB66E776BE36ABCA8B878F47072DF26EB2F52", - "hmac_key": "C863DD8C616E84252ADB5C42A45954744EB762A21D7FAC9A7994B45C21E4C677", - "adv_salt": "56E2", - "plaintext": "A55F99D538CD53D1E18270420BF27FDB20CC7C949ADA1332A547", - "ciphertext": "71AC20DCE1E5E1A81866DE2A2128C4BBFF2984D94387604C366C", - "metadata_key_hmac": "11D7DF11FE83F6F1A64A45EB4D517C750BEA1B1433C1649DD4A2A7021F09B0C4" + "adv_salt": "92E8", + "ciphertext": "9D7A16FF9BA61DF8E9C334DFA7DC4CACDB8E", + "hmac_key": "5DBB733D2B294A0588CA8269C78B0DF193248F1C57162DBC2964E4555C7D7A43", + "identity_token_hmac": "07CDE87E1ABEF617ABC4656486ACACF06F374CB1398321616535931073C0A679", + "key_seed": "9838CB399FE0A326FADCBD72741BFC44D7E3931B8DD1548106FD6B9EB2E957AD", + "ldt_key": "6E24140E0ED82DD3E8F438E00F9FABF0980A8B19119F077A294AC077F4662FDEDB96ABB3E60C700E926595A96172C657DB31D98899F4DECADC200360BF658F0F", + "plaintext": "E82C53A487B1F338B2BC803C600BD9A02096" }, { - "key_seed": "D6D25ECF88E2502B7671472B6A552B36D67B9CB9321AABD1F806ECD314FB9FEF", - "ldt_key": "DB7A65F320FB5013BCA14C176A00F8C1DC73F49ED05BE2C1E378DAAA33FEB5F8153C201C4E82A6EA6D5224D10781EBC271547640C85E55FBA24A3620A79D341E", - "hmac_key": "6C6D5EF7242CE23D098FF85950E838E497E18450067AFE46DC58E937D909C484", - "adv_salt": "0E30", - "plaintext": "4F4AE5C4AB5DC7FD4D3E8929140FE83D32C59D9EFD84", - "ciphertext": "DA443DF8CCA50DEB682E1714095280857CA6F4AE6166", - "metadata_key_hmac": "3E602FF8473A4AF98A4AFA779C69B468099DFE47A6CF5DEA74E24974EDAD64E6" + "adv_salt": "9383", + "ciphertext": "4885E9C9E997A4B971DD11E3E77290A98D6D478124", + "hmac_key": "425B973660A913AD6CB0207E02AB0F345A89B508778E5416A01FC632D73ACB5D", + "identity_token_hmac": "1B0B1D1F74FAC903899A010DA97DCDA03EC4374730445056BD13AEB3A7CDC0CE", + "key_seed": "CDC7DA21484EA21B0BF595BBD199EC129A80575FB00AAA54AFD79B0EE7823439", + "ldt_key": "1D9FC4B353E8F42FFF9216EB74A63288266299972A2CF73AFC649A07967FA1096093CD34FE0A14B257AE04F616BE0729C3A782CFB1381A74EABAE8AE26A86644", + "plaintext": "3A4D5D67AC8DE93A7D44473D846090A8EE4EA0E875" }, { - "key_seed": "4280AB46666D4D72EF2BA5E4F09F4A9B515A6211A5594F5B432E16704C06B65C", - "ldt_key": "5A3ECF4BCFD13F57049CB026312CBD9A082A84BEB0D5B8BED4A0958D890282E1C42198FD2DDA2C567D9040F6B3514D1A6DE327D961AB398D2C5E5B381F2AE297", - "hmac_key": "3CECCCCF1E22B4792EBC15075ED2119869A066427A857B97B2B3C048642902CD", - "adv_salt": "EF02", - "plaintext": "998488E3D3E1D033E6E11CE1BD83DA51CA2AA4D22798126218", - "ciphertext": "19ABE26D88D0358B9E2A4F74FD05849025CC0D8BA531F00DFC", - "metadata_key_hmac": "B2E23362172A282DE1058FB0349F897B0C346917F45FD8D9478A28E0230454D0" + "adv_salt": "C210", + "ciphertext": "34DBDFB607BE2B7D28585DA18509B3E335D7979AD84C5F", + "hmac_key": "8B2575D2DBEE5987CADC9362900CE93ACDC0EC0BB7BC500BBE64EBAF50691E4A", + "identity_token_hmac": "761325227F7FE98C167C9E02CA7820151C70D304E6399356050D4355CCE99D62", + "key_seed": "758AB716E1EE6062613F2AF07F136225BA1965BA8899AC8F5CBF947C048B3624", + "ldt_key": "F72B9009F078D118108CF081507821DA62C4522FF2595679B4E73E003E0BDAAB8263EE64BC4C62FD0AEAE0F635C1B3757280618C337E1267726183C18AA2F86F", + "plaintext": "8034DA557861DEB71ACBFAF06B2363E2217A842A0282DC" }, { - "key_seed": "29688FFC6D8199FB3150EB61CA566A52F4DBDF34C91D4D8F30722665C7C2C8C4", - "ldt_key": "163A0881FAF42FA1B43EAD48D7192487C6DCE42F819A8C9DFA44FF71E0EF830793D9155856491DD6B6CBF44ADDB002465D7D6C06D9F43ED0DFBE5979EA3EE6D3", - "hmac_key": "C55C11DB9F8DB61E96D276E0F27A6451173095D3CEAFDF78E4AA824ACC39E42C", - "adv_salt": "F215", - "plaintext": "76DC9C1687E162B8A6F5305921E25D4F2309404CE35F570603", - "ciphertext": "A9E1B8BC917BAB6914A69E94564B04073988A489ECF2A8A545", - "metadata_key_hmac": "C3F4F141C6B6B251DA07F07B1BAB1572E6A41C08052C4FE50C0DADCCB5898F37" + "adv_salt": "4932", + "ciphertext": "18DFA83D270515BA234A700C014DA5D6EB53A3F74F5AEEDDF9792B0904A3F5", + "hmac_key": "F9DA93ED8A58CEE5875A0A57BA00457441F1DD66114DA3835CE947F6683327C6", + "identity_token_hmac": "B61DB6EE722BDD44FFB11AC3187BA9F59D25B726D3C91963A1B92ED2E68CDE63", + "key_seed": "170AE50C4C3D672E225AA92AC5414FD3B7B5073073A61D50DF3E36044EF582AE", + "ldt_key": "766F6E50B231EC7692A9D5B1CC14A009B7AC6431A642E2CE219EEA3045E7EC45EA0943C823E372057962167DF8F57C916B3D0BB9F7D7B0C82EC80D4B947B54DF", + "plaintext": "116E13593BE0E8FEE54932013E43E984AA7FF6C8C0A825AED747D175BCF2B6" }, { - "key_seed": "DCCB95471CD9428172C964CBCBAE520CDB3914FCB751EF98EBF864796729D8F1", - "ldt_key": "CF452D0A9AACA5C57E3D84937AEF3730F5EF28C4C2209D836629E9DFB32F40DF7F0C8524335C3FF39EC6091CE07BD720FC232C3910C93559335B98CD9F2890F8", - "hmac_key": "321262ACEC4F28F2882C4D744EEAB2684933B3954E4C1D33C462FC28C0FB913D", - "adv_salt": "32A5", - "plaintext": "0DCAD7F90214D1FEC607125A95BA4A0FE8A4", - "ciphertext": "AB0DBC14F08558984BDE7772AE0D88C01E47", - "metadata_key_hmac": "134A10970EA11BAB8D2BB41B253D91B488F0F34ECFEEBA74C5A4D314D39B386D" + "adv_salt": "ABB2", + "ciphertext": "C4075AE6956FCF87B34F8E4508C94BEB414AACC0A386D7", + "hmac_key": "8DAECC5753E47A2440DD3050160DC457F3AA0B6724AC5AD8277CC2AA4E9F422F", + "identity_token_hmac": "9556EC591F5D4B96CF0D27E081274D32EB6B842AEBC0F1440180B80E44415435", + "key_seed": "930D256D59C815A9511F10774CE147419026A620F262F5237FE1251B93505FD5", + "ldt_key": "20FB37DF50084F9267A8DC7A9B7BABC66611469FF26480807458619D63275A34C37836D07BE5D47CC03348A8A8BA96B41DD39A518B6E1AE4F44CADD7763DFEAE", + "plaintext": "4171C59B3CD3F41D44E18B6AB8876873DDCD25B9EBFFF1" }, { - "key_seed": "602741B32088CB24744C42AE8A04F4FA1D8AAA395CD14BF794785AE906EA31B5", - "ldt_key": "9E5ECC1A36F9657D73D7F3609BA66A102DAB5D0343D641A07C5019CC86B813C25EDD9B6363BDFEAAA3403C061C8E84C6F334E4485A5EE988404EE98DF2F90CFA", - "hmac_key": "546DFAB1F8DCA2B85752D25B5C5AFDD1ACD8CC9B380920C529C0CE70C0B1BD55", - "adv_salt": "49C4", - "plaintext": "1B9CE96F10D577C41A523A2D4D75F2820FD811E14A3AA4", - "ciphertext": "0317B287D59B35AA1873CF36B3403A7F9616FB0943BBBE", - "metadata_key_hmac": "47FA521E23291DAFB3DE6121DAD692496392E939E03368506F66D701B4C64CB0" - }, - { - "key_seed": "C43B0C050E0BEAB285191146BBA474189B253D78411FECE31AB5B6EE60253E19", - "ldt_key": "9BA205AFD03BF4BB04AAD928C7B6EC29D2DEDE9C98DAD5C5E036E7223D450BF3DB6FDE175317A6A1E26AF0080E5BF6A637A9C1AE0AFBFE15DF5454E0D454F138", - "hmac_key": "3D97AC87FED97DF4183ADF57F341159C847BE13712B82491C8C426A0D5AD7B3E", - "adv_salt": "9F08", - "plaintext": "F2B228C059D4CB0F7100D8C0B5C78EC9DB7E8F141E0BB9", - "ciphertext": "EF71E826D9243560EB3BDB751BD5679872A821C2DAB9BF", - "metadata_key_hmac": "C255EA0EECC08AFCBB47D033DCBD78F7E30BC0CC70F21754A8C523BF17DE3E9B" - }, - { - "key_seed": "E3CB42EE350C452AB1D96DFFAE79F48F8BBFDB72149C21C803A4B50B8E1BC4FA", - "ldt_key": "F5836F573D7FBCFE83CB42451F1A50A535BE11AE71F9BE3DC92A430A144F3641F9AD55B29420F09AE423D6B2B64BB57AB4394EA8CBA8C2FC294E419D80CC61FB", - "hmac_key": "17B23A47EFEE4FEA1DA852F13EFDCD928E03C0E38BAB4F96B6643DD975A0ADBB", - "adv_salt": "0950", - "plaintext": "5655DC1EECAC7CD61B2DAC897DEA832EEC27", - "ciphertext": "82A8293E6CC28C0A185145D1077BEBE76EA0", - "metadata_key_hmac": "D97EFE52AB79CB84682B1AD131F1E46370986C1F24C819FF7BC2598FFB911051" - }, - { - "key_seed": "DD858E3C02C5381C800757E996D2FF45ACBCB00A01A21DAFB07FDC3005348E11", - "ldt_key": "BF41D6D21D47EB610362613179227B851BDAF8F41DB4D82644CCCF0D1B2AFEEFBF91B3AF386D7741CE4535C6219C05C89FFEBD4F8C796E04744386736F9C277E", - "hmac_key": "7CA36BCC67F15C0DDCF071873C230F50468E3AE48F87F82282A83FBFF377BE55", - "adv_salt": "ED85", - "plaintext": "A9164F9B6C63C4C34E3DB34DEBD9BC6237", - "ciphertext": "346F3DCE5DC5778E368546F7CDB1295BB6", - "metadata_key_hmac": "B953BB4678BD924EEE6C47505817E1E31EA0FCD21995C66299EB43053DC0F753" - }, - { - "key_seed": "2C8EAF66387544DC932D47E665130C17AE350BF726A1378ED17E08DB17E32019", - "ldt_key": "C1615130E0EF37C63115F80E8821C5306657E9886F37D606E3F6D4A21FA1055513D759E5F0F9F8B21EA215F690A23B7BA4BC78E56767E05523ECC970D5A7FC10", - "hmac_key": "090843CE6052B02B53F4D1B479623014360C9EBD3112FD72301C2698AE55087F", - "adv_salt": "B698", - "plaintext": "5CA984CCDD4AF7C3B24C92E8D23A74446D1E647E", - "ciphertext": "4784388C98FAED88883F171E2FBAB3C3D078B573", - "metadata_key_hmac": "9AB7AB93238D92FE02DEDAC29C775BF9315F3C696079DD72BD88C39EFF7AD0F7" - }, - { - "key_seed": "BCC181A2A53F1E9A2B17DFFA213BA37BF056D2C1FD74E7F2D81A963654C5840A", - "ldt_key": "7B06F03E6964E98D68FD2D03CCA2F029E8A355DDC944132B4B36CB254F975A5B10DE495AB16919493E202B2D74924776DD675A33DC09104EB7CF3CD3094A6E31", - "hmac_key": "D651C7D566DDB461C7CDF0D6D0744AD6178658EA4A118465DA88052D9351F3D6", - "adv_salt": "FE1E", - "plaintext": "2EF24BEF273B15A558A8C1BBD415432AA4629D7A0CDBC9512F3DE2", - "ciphertext": "F51E9690D234726CF856428AE1373FF1940B778A8ADA54C2B867A8", - "metadata_key_hmac": "04F92ACD86FC2ADD7D1DEB7FD53D7E051F8E3E72EBED64515C1EA83DCDE19982" - }, - { - "key_seed": "85787F8AE79A46639CC2C9F2B4B15956C7B92684F5D0F76547A7290AD87DDED1", - "ldt_key": "9396EA24153EA5CFD00969F044045B8665E89CE9C142C64B7BBA8C64D27C8A2069479AB3D69DC7D01ABC9DE07AE02343DDBD06379A297B83FDB8AF08F846E425", - "hmac_key": "E651170724729345796297608F276F262898CE7A66E9E948185818039783088C", - "adv_salt": "4D4D", - "plaintext": "EC0D0628250421CFA7BEC2EA26A7B435B4BFDF4B", - "ciphertext": "31CCAD29DA8E68183240107590089717669706CC", - "metadata_key_hmac": "EE39C3235CE44E3C991025B26E1159B784D46AC6F1BB2919BDB1E64759B7F478" - }, - { - "key_seed": "808A56F86617F0A36E403CB6448531A6C9A41CD37008FF1CED445DD60C6E806F", - "ldt_key": "5841CAD4189E1396E561800917C835959E27378CBDB2AF33EB85116A1F1D4B1F9D2DCE40C5B4C5C12884E3D217000DFE1EC74B1AD17F34AEAD8DA086BCF3EB27", - "hmac_key": "ADE211D812886EB8D68406DF336CF870056343BA4F100948EB559AC4F917D2B3", - "adv_salt": "F7FC", - "plaintext": "85528B7B4972632BEFCE2D7C620747C0BC4F7B2C7008A9", - "ciphertext": "09C2D98933F2A751F548379D134CBB090F982F524DA2E0", - "metadata_key_hmac": "E561E0870430A5DD125F5E07A1852EE41E11F2344618A0F3268CD3A9CB7A0CD3" - }, - { - "key_seed": "CD451867F408CE5CA056E3DDBF393B35FE2028992C896AB15B131FDB146A4769", - "ldt_key": "B3DD3D25B37B532E81979CC31C569399F098955E20E69A066D2533243AA32BCFC2D632387A63340D0646B227AA8C7CF03FE2A73D7DBFE5B7F3EB61C5453141BE", - "hmac_key": "E84ED8653B911533417D6B408EF5BB2025965C9B9291104BB44C00FDF19A3829", - "adv_salt": "EDD6", - "plaintext": "09E16923D27569CE6DFE8B8A3180D942734D", - "ciphertext": "7DF216E4FF81D7A86A064FEB71B54F8892E5", - "metadata_key_hmac": "15DCAED4AACE7F57D8FDD76921E60C110764E895FEF98ADBA986A239D98EB18A" - }, - { - "key_seed": "7ECE23377DB5101629A397DB13EE9238DF6A707B63E59C214574DDECD28BD77C", - "ldt_key": "E5EDEA1C2057199A79C34AD5F16996927FDF147021EA2900732D8D90FD061EBEA850D755584DCFC419CC3AAA48372BB63C555EDF7B414D7AD5224F252E77BBA0", - "hmac_key": "A8BF38403D85F2D77B8F96B01BE5C2EF2E35B0CF4482DB66F5672BA407B343C5", - "adv_salt": "6390", - "plaintext": "9D6329A4603170AAF549CE2E49FCC674B9AC131898FA14", - "ciphertext": "0BD5FE354CC50817D766DA59E359BF06833FA85595DFDA", - "metadata_key_hmac": "48B79D27909917BD5326C04E7D22546C8777276179B70B7F0C8C818EE067E06E" - }, - { - "key_seed": "15D576484E9214D9FAC931EDC67E091420EBBB7BF019AC4855B758E85D3E9412", - "ldt_key": "308E191F21847FDC8319EC46D49FB4B5593D351187EBA1C457EC08ECDE1234B4512A73082E845B307597E2758DD05A2F159D95C309DBD7E1BBFAF026E9F675F3", - "hmac_key": "705E54F5C58D5283231ACBF76CC81D1D602D1400AF5C1B6ED88B00E972BB995F", - "adv_salt": "95C2", - "plaintext": "5EE8F009FDF3707221F764A57B1797FBCC8803652ECAC995F2F422B65E", - "ciphertext": "C3F567F4CB422B630E520FE921E10176F3DC751FA706AFF159DF7D16E4", - "metadata_key_hmac": "089803428F05209A06F2DC80ADD9B708AA3F590C20164914C42A3F1E8F3D0A91" - }, - { - "key_seed": "C1332895B13DF2ADCD2F87EF068BF9ADA96BD121447A2083E85BCC430F9D1680", - "ldt_key": "46BC3E82A6192F62AE5FB0DF1F84D690432D9A3883B6E755E5F2BC40A20C56E4E699DB37C5B2DC7552C58DEE84CFCDED48EB4FAEBB2782835F9432CC9F19BC96", - "hmac_key": "F75B7EC653D60C812B580405DFC9286E79A673597DD68AFA463CB8EDFDA2A5F8", - "adv_salt": "AA7F", - "plaintext": "1385F3E5B01E7667A39491CB78323792605041CF2AC8", - "ciphertext": "13A0B7C490E8C88160A80F667EBEBB89B6867CB7010A", - "metadata_key_hmac": "3526AA9EC81718F0A7354BA0C97DFC09F6151A1BA94B07C9088C2DDF6960CF89" - }, - { - "key_seed": "C8FCA816F18F73E3F2CDA9156F5FA2D92FD91053ADE867F0230DBA4E2BA1E3D7", - "ldt_key": "8D820238E3F19CBC416753FF3239099DC5985EBE202780EDE7B6E920BD97421ED97D1FB2DC91321E2A702BB32DCFA4EE8E064B1B949C6EA21E828DCD617F30E8", - "hmac_key": "AB4E747A286393A9A8D4D2F54F8D4BC3EC07B6268D47362ABA14F037B80338CA", - "adv_salt": "876D", - "plaintext": "A16A9A2052ADB3E6AC2529CFED7EE211E58185647817E697A1570D", - "ciphertext": "48316F94CCBE262DF3FCF476CB8A0AAB475C9936B5DF0055738684", - "metadata_key_hmac": "917FDBFA129F192BD9616B44165D2202F063BD466DBF9B4E3C3B75568BF76282" - }, - { - "key_seed": "639D87014289A8E028BCE63B1513502616ACBEAAE521919E91693F1357E62E0E", - "ldt_key": "61B7EC75F4F235D492F3AC35C514E0CBB6E350F85885E6FFD2297465958497E8EADAB8A6183AFF23BB69271F4500B8B1BEF9C6F7C9696588F8369664FB79AAD1", - "hmac_key": "4DBF3A9E6B37A014DEC9A15C73B000F10F7A1AE631BA76AF7DF3357E70980669", - "adv_salt": "2E76", - "plaintext": "45C44EB1CE23718F084A97F47FBDDCB1", - "ciphertext": "A0925BD133932E2467CA67274227FA55", - "metadata_key_hmac": "1F076DBE5AE63F71D4D5B23D99FCCC2BBB7CF73F22EDEA0B1C6A58035867D519" - }, - { - "key_seed": "773E33067D43FC523B4305CA3578AEEC24F8427C3B3959A347EA4B7E50A0CA1A", - "ldt_key": "20F2936DB1EC57420FB7F9C24702CAC1706EB3E2BA44B80603A1511A32A29379A78E8B96A532D1A02B83590CFD2295FC5E9E327E9ED521A47103F9B934AF9AEE", - "hmac_key": "FDB438716D1EC94C1E0B704160BDB87C293DE9ADD5D1C1370A91BFE6FD2426DA", - "adv_salt": "D9A4", - "plaintext": "377F605140CD99F7CFEE12D57478DBEA648F55FF925E0B", - "ciphertext": "B0D28A4B39A01596EA5363374D0022BF17CAD42B28F175", - "metadata_key_hmac": "7BAFF574972DD155FD382CF6C055FDA328EE16C6F14552E4564AA76165AD9EC8" - }, - { - "key_seed": "9043994ED8E3A349A66399E3D047EF6AEFCE13DC97D3BE218306B2B2C74F1838", - "ldt_key": "BE0EB7D950AAA7F181BB8354D988AAD2B7292F0DE1D08DA041C559443615D13D335ED6094EDC03F96765A4793213F64378EF6F3B59B15F939FFE095864CAE903", - "hmac_key": "2D1204DA558E5D4CB76835307D85D27A2515AA6841901EED119CD54571F17235", - "adv_salt": "0247", - "plaintext": "CE4A19AFDE5A8B0D45AAA57D63F43AF2DACC59", - "ciphertext": "65DA4E964B043D38A74F9C9C50AA3BD0A52AFE", - "metadata_key_hmac": "651BB173EB8AF1477B3FE8497AFAE9DBFFB6F9A782E8789BAD2945F229B0E96C" - }, - { - "key_seed": "33EAAEE040953BA534409FA76C8E1007CE3E96589AEFFA84CFA1074FFA796C8F", - "ldt_key": "F4691E3AD571F4D034CF12FC1926C35A238A125E6BF1FEF0A60F414072A9374654C98368EFA72F43E1F721984584343839C3F773D2BE2D7EC113D5C45FDC998D", - "hmac_key": "489876B3B546151944E9BF68F313FF85A57E4F0AA10AA937AA01E5F38629D8E7", - "adv_salt": "1FCD", - "plaintext": "CAD15F38FEBA1822DF2FF59D9D957A1E45F969BA2CD6EBD9B21E1A77ADD5", - "ciphertext": "374BC96155E859C94B54724C63EAD5AA48EC1EAF80DA58645CB67D1596E4", - "metadata_key_hmac": "DA193D7A30A6A1BB378086C7268B588F72FEAA7C4D55E23BA6D6D8370D0FC6B6" - }, - { - "key_seed": "DED6991887A8DF6FEF86818BFA5BFC500EC26A8A5AC46AD0930372CA853171EC", - "ldt_key": "7E450BF4E4FF15A0170409A3C9ACE09A56B68B5C767758E2D3C0092CB5E2496469381D9F672C7FB79A377B0B8CE1ECA3A1758AC53200EE5AF9B5840756D168ED", - "hmac_key": "6F2CBADD9A623201139B518CD064B84335CCB95C51880FE1703D8165A9DB73FA", - "adv_salt": "93F3", - "plaintext": "415A1BBF0375F9BAEAD6C8F12C0871991D2B9769E0C0", - "ciphertext": "C319812E0958DCB530583AA0F86708C5910689032E2B", - "metadata_key_hmac": "608A1CE3B8549B766BC485325CC22A4AA35993D8258A04DEEE1B4D3C3A2E24E8" - }, - { - "key_seed": "8F06814937CC1CD3DEE445766BDA35802F1F90DB041696BCE49C9EC57A5EADA8", - "ldt_key": "D10BDFB216C67FCEF131FFE348A709DF30FA6DBC3DD3EE24871D164DD2F57FD5F4F02DF7F2C3749C29C75C79D9308AEA094B7CDCD49736F44E178C9E000954A9", - "hmac_key": "D21C39E1A8DC4CBAE82347B4FFCC25555545CC5FD81C6FA44C53A13E1DC18634", - "adv_salt": "6C7F", - "plaintext": "370B54A52F182467FE71B162EE0B7B13B820B6066F00", - "ciphertext": "565661CB8811F9FE7F76050884763A1E18C3BAD52061", - "metadata_key_hmac": "79B8C81795E9BD20CE806A3D043A6B09BD2ED0E60776718C70A06583E8123AF9" - }, - { - "key_seed": "F9BF622E0E202B09C7064578FE5D476152BC66E22027F9CE1EC93C3598E023C3", - "ldt_key": "6ECE9BD2599C407B78833FD38EF430916958136DA9DC298899380DE639FE5BC28CB73A9422528836D7F4C4333083CC70B5B209A82817A9BC598EDDE465071A00", - "hmac_key": "8F8BBCEAE4BA15C98BFC13FB9E6128546F8B35C21A0436F9A268F8E0B3C750D0", - "adv_salt": "DE64", - "plaintext": "EF149B9523C59260F9F1BE6E5F398A67462D148D54E8F736C53C8DE9", - "ciphertext": "472FBC227FE51F9665473D5E4766EA430B19F8D41B4EC681ECDCE762", - "metadata_key_hmac": "EF530F925480E6119B9756EDFF83D85AB8B9835B7C91B4CE73D09EEBA986F595" - }, - { - "key_seed": "5A4535D6C65E6F6C4331DAA9A82AF970C08EC5494997334E549B0BAFD8BD0EFB", - "ldt_key": "A49522B39E6F1056481CAC2813290655A0E3E5C5D2B6690ABAEEBF443C69FCCB2C92E13358939D5BF76492FFBAED6597B4FCD1FF197C3C20E14F957BA955D388", - "hmac_key": "A0CFB7E0D37BCCBC50338B76E303656B4AF45D1E4CC30D30D89CD457F7B203B9", - "adv_salt": "35CE", - "plaintext": "95928C9A06AEFBDA6A7CCD95D5EEAD60B088ECE67A", - "ciphertext": "DA6ECCA8646CE06BD84BF18B112FBDA195C9096CE2", - "metadata_key_hmac": "CFCE2919AB5341679FABFE8BEFD6855E4EFF443FF352872DF0F67F90B9543D5F" - }, - { - "key_seed": "A1114E41B51E081227AB06CDB0E5239DD13B0E97B31E6EF8F8701A4B91636E30", - "ldt_key": "9441F2E6D59C21AE024DF96AC18A0BC769D0F166C4B68A5F1F926F53D2DB81A1D4B9414CFC365702A082F123F7E489EECA948E3DC8B78E7CC3327BA5C9AFB79A", - "hmac_key": "ED4D3D7846C36C9A7A29A55E304EB86DD67ABD8C42DF57C7F2704C15F450F782", - "adv_salt": "2FDF", - "plaintext": "59788107CA48F947B2855B1771A09C45B97B4C024198679C", - "ciphertext": "75928E663962012B017FC65FA716FB2C03AF4E6767650348", - "metadata_key_hmac": "7732C6810745DB6910FC1E4821F965405D9E48EA675AFC93F893EDBCA04D564F" - }, - { - "key_seed": "4DB0975D2F6D6B3EB12BB3BAB460F4386D5E88AD09E0B457DC3A1C55D94751D4", - "ldt_key": "BD51281E7EC90564A5A29F85C8CE6244035D29261DAACD4D81400FEFB365A43B56AA8FA651F83CCC314B6B84F8FEE157ECD56AADF1ECE204015BB75840FF9348", - "hmac_key": "E2DB87BB9D7223BC2D71EAFC91FA66E11CAD6EA0BBB186839333FE4279F466B7", - "adv_salt": "4E0B", - "plaintext": "A91467F408F444CBED194AC5307EF4181646", - "ciphertext": "B97D2305E905784DC692289E2D64023C0D56", - "metadata_key_hmac": "3861175C0B2B74A0DE6F1F39CF59C8FE678AE79B6253BC48E008C140EF10C481" - }, - { - "key_seed": "BA648F4E0AE9AF10F05104F2FBFBCEE0BB1FA0355555680C571132181D05F1AD", - "ldt_key": "896ED7242321DE997A3401BE142A595016F3C54642C6274925208BB790C6CE89F2534BC74B5629A147A2990E5CCE163CF1242AA5D3C888B760A3091653C8E1A5", - "hmac_key": "73E65E7E0EB5B624AB34163A2FEBD7388786D74E4E080DA8D2D292935183F058", - "adv_salt": "4653", - "plaintext": "BC2FC7A078DC86A8511D8E332380EF95A839", - "ciphertext": "FF06B9495E0F16393DE9B7B64F409A582807", - "metadata_key_hmac": "5F55D0F79D6CE882DDEEC1ED316E4A1732CA9D3DDC62B6B7EF38D005DDED3A26" - }, - { - "key_seed": "6FF5DD9A8638451D09EC42FE83C60F743A4F14049C3EA102184F8192EA0792BD", - "ldt_key": "1D767FB92E69710B6D0FBF602BDD07F78FA4B6C8B32AEEF1433BAC04C55ED6D0CC3F96D2843E6A856ED3210B5AA1B243568A8E4A66B947AF4C73C0401EF57906", - "hmac_key": "CB419433BF50E8EDBB7D99757E4F6B44C08F1B34B39F43ACA6DBA1F1E342687D", - "adv_salt": "431D", - "plaintext": "208A5B5A5E3FBD6B966A48450BAE7BC142DDDBF0E406BA0373F1FD", - "ciphertext": "0BD3ECA5EAC8A1CE354FD6673AE0FD4C5FAE891D17D1243F89F16A", - "metadata_key_hmac": "2ADC08969BCCCFAD5CCC65C5EC5EF23E153A854AF479D82A26A68442BC40C682" - }, - { - "key_seed": "007179CC6DFAC2206616506969B8B4523DEF33A7484A8422420387CF517EBD6E", - "ldt_key": "6547DD1C3A839BD25719F7086A39416A2A5F2127F04578F7116654A22B65A20229A2C89FCCF1C5A3AA90FC1321A393517C05278843B0D01996236CD747EE2F0A", - "hmac_key": "A93B1379F258266D371399EC911827037CB0F1A896419FA50F66B638D8B56498", - "adv_salt": "8CED", - "plaintext": "EFF413EC2429A863FA47ABC38A679DF714D7335F86E811288F82590C90D1B9", - "ciphertext": "8F2C11EFAA18DA47CCE6BB05EE70B7F4FCBF25A51CFF41F440A0B938ABF006", - "metadata_key_hmac": "1C8910D812CDE5B90D80615B93182708BB4E32A6D29DEE96590DF47B9AD5E2D5" - }, - { - "key_seed": "8EF6C0B1B0F45A0C7A3DC587544D5AA38FFDA1E4486680CAC2570A679ABCC80A", - "ldt_key": "07A9127089B82445D88A4F5503F909654EDF75D5E56B5DA358F4C0A3E45312D84CEEB8E4DCED559DA036DA236352116691442CC07967A79F73CD47EB510E755D", - "hmac_key": "9C64EDC9C36ADB8F20601DFA9DD9EA6D116A19C3CDCA6E69A5F0DDD4A0B6D31E", - "adv_salt": "1028", - "plaintext": "2AF3D2C7D0CDC8EC583521C17400F4D3", - "ciphertext": "5D92FBB35A5A032ED4042E3803A646FD", - "metadata_key_hmac": "E376FD42A95C169E444B04AA336053445A3B29FE947A52F0F907982AF03CB879" - }, - { - "key_seed": "45AC70DF90E61ED6FDE2BABD2DE9DE4F2B818D9A1D52CE8CDC56F53F0D6397A0", - "ldt_key": "BAFC221A84DCCA1B5ECFEF66DE66497547131E8C4548B6353B013111E76E02447429A86A71BCC50F02576C4E75FE789C5D0226B979A97EC8FC63600F14AA281F", - "hmac_key": "C30D9ED8BD299EBB5CD23F86EEAE1068635347D7B5061FBD17C34CE9A14382A5", - "adv_salt": "830D", - "plaintext": "4F4B6CD3BDAD13388F03E295A29734F1AEF1", - "ciphertext": "F1AD9D75E6013C892EC19A466BD346732C35", - "metadata_key_hmac": "3D042C46EC4B53B9BF2C301C02BB137179037B09529F12A816D04A8DBC94863B" - }, - { - "key_seed": "9C5113AEE454EDFFCAB89C356831E822F76FE28154990FE13186438663D75A3E", - "ldt_key": "24FB6B83E745E019E071368C902F2ED6762D87498A4E14AFEEF4210BFB2A9E0E9953389C9D5E0D60BB337801C1DE1BFB658BBAE4E87FA943BF6FBE824E4798F6", - "hmac_key": "AA068CC06CDED1EB64ABFF4B28DE707FB2EC585231788F3C319B7651563CD17C", - "adv_salt": "A65C", - "plaintext": "104736EDA44F39305A5CE472049989DAAF9972B35DC8", - "ciphertext": "532D6EFA1313457BBA6EE436609DFC11DB7B4343B781", - "metadata_key_hmac": "ECB5D9170FE03D317E5A3EB11C4BC5F8F8123A7A3DCE3E68CD4B547707DC7C74" - }, - { - "key_seed": "29C157553B7C46F058EBF29D6BEBF05CCD33C943AA2BDCB5510B372861CB5F78", - "ldt_key": "A3544DC50715B43F8EAE5A307696C47C061CB518BA11805A7161877FAF26D1F2854FEE2D0249852FC2D93699C945A74A6E007ED2C33A3B7054869BB2DC951BB1", - "hmac_key": "B9701768F5AC2E7FE0FE2784412877AF4124B7AE53E68B4CB849F81683E3F057", - "adv_salt": "D44B", - "plaintext": "BA6825C31151EE0722F26847F99281307EAB86791A9C61C2DF7A7E0C", - "ciphertext": "43635813DD9653DBF32DF9CB0469065CEA7C6ACBB125D3AD9EEE658E", - "metadata_key_hmac": "7E27C5D993C851B84ADA7F432D513C36E8F6D491CE47FD1B0C06825F04F932B6" - }, - { - "key_seed": "B0EB2DAC5710C79EE1932CE8F17FE4D366547E7E2175C1A712E1F44D4C2E2108", - "ldt_key": "6F74ED8ADF4005EABF1E018BC8569185508A8D954A7607B68CC3CFE98832D0B2210D4C069C0F5FA6AF7208287C2B068D67730B8B8D82B95B47AFFB178677A9EC", - "hmac_key": "FE7F4D7A058B1D6E15A70EA481C34AA0F0D6A44FE36382EA4BFBC3C7E43A7298", - "adv_salt": "B2DF", - "plaintext": "EF23D6F6A1CADE520DF4C25B4A2ABF6779A9DA4B361F6DF6FB", - "ciphertext": "0D79F1106EF4E722B2C8AD1AFC5BFB1F7ADE166221AA5F8016", - "metadata_key_hmac": "B721CA7742066F65D798FB714CBC55B64E57C9BC7DFF464C2571DB78CE88280F" - }, - { - "key_seed": "009A9F4A605A66554743DA0E493F9A33C48973888D68FEC628E449393E5FA3E1", - "ldt_key": "415C4DD2919CB1F8285604FFA82E5FAEDE8A4F186F77370A509BA6FD4E3155AB16326C8DB36FDD685252530D041792A368C092DD9F4F020CDFA8B42487660188", - "hmac_key": "734CDADB4DE10FD4F9159C523B0B62DAEBE653A982693071520D6386DF4979B0", - "adv_salt": "46BA", - "plaintext": "87D22D460F1178F26FB8B537374856825563264F3908", - "ciphertext": "7FC280353C298F5AB2423B0CE4C2E756601C4A1C395D", - "metadata_key_hmac": "6DE60DFBBA508C7A30059582BBB6D74C2D4B14AC6C135016C304026FEEEE21F5" - }, - { - "key_seed": "9E86CA768B535DB61C0BFDBC1FB5D0F28B5499D0D954DD90FF3DDFDB90084C07", - "ldt_key": "939105E8DA13970026CFC2E622D8880829FA89214F3DA76A6BF46A0A816DFE2633877871D2CF4F093BCAE6B40DE7E9F65D0522F2577943B040BFCECC44BE7148", - "hmac_key": "B68B131100130CF46E88F47301774490B99DDA1E397C09D791FCDB0F5B3F4CA9", - "adv_salt": "D581", - "plaintext": "8485BFC1ED2472C01D6AC692C7011A92C5E4B11E", - "ciphertext": "35B09B08491CB095260EE18F971B42A7EC8408A9", - "metadata_key_hmac": "739FB784C50F16B18DD48417E91447AE7E5AAA085F217F3C32CB9070ACC0AB69" - }, - { - "key_seed": "DD5BF59A0D1FDE574C417CAA8D9B154A16A70310AC9ACD548F01AE6F48AF0A2F", - "ldt_key": "6A8139A5BD21C918C47F00DE8C711A8E19B87DF67BDA7AC3F91613222365FB2ED0248D574BDC0C6CDA67E7BCCF961944E818DE916A3DB44F7CF75FBA2D339255", - "hmac_key": "C0F6FE0B6811C5DE637B0F775D7388F12A6AF805C9E0B962C21513C4A6519891", - "adv_salt": "C7D8", - "plaintext": "5C155BDB14AABAEDA8506B901F62BFC06CD1B24AA2C9CDD2C224", - "ciphertext": "5AB031D04796DF77F2892C4926E90D2DEB1E317642161FE53142", - "metadata_key_hmac": "D1F6F0E2B8D9F1760FD3E76B5952E56A1442F2FDFBA2BC6ACB038A2554D0189F" - }, - { - "key_seed": "A9302C3763D1B55F5F1086D4255088942B2AEA3794FED75D9A02272AE2A460B3", - "ldt_key": "A909626CEC0F439B0AD454A66CD0748355DA03D56D69309E86B89D34C06A021CA7DA2A55A5AA86373484C4B110019C54C84F1D19E2CB7CFE3309F98D24E9F78D", - "hmac_key": "2C67C798D5F2DB996C6409ACC8E3C712FDC2735261F18155BF9A4F2F23ABBEAB", - "adv_salt": "4D48", - "plaintext": "67C49EEC0D0B2189F7F57AB202C70ED3BB573A", - "ciphertext": "BA6C447C9DCE15414014E1F6EC1175695D07F5", - "metadata_key_hmac": "ACDB3D18AFB857EAB7E9AB74C72C8B8C0796CE5AC81793E7B1AFC29B8ACABA1A" - }, - { - "key_seed": "4FDD1EA1F83E8C1E076E152841D9D7060A25C2CD08886D91AF5407A54837782B", - "ldt_key": "C5384D76C40CC48114BAA1E2D7E5F4260F8D9E8324C7D358316D2045C7C3F50DFFFAF41DFBC8A6B5D8D5E6B3A08B85FBB1B6054256C5066522C027C7E9501DBF", - "hmac_key": "66FDFCE8CAE843E394B3B2DC07359656C07E5013D7CE65A75B62458288420A88", - "adv_salt": "CEF4", - "plaintext": "F99804807B744EF30BC27605453B918A0CDC314B", - "ciphertext": "9B6568B0BCA8AB1C8D15AEB5D97DA2740CE94E01", - "metadata_key_hmac": "D31CD9242164684A1A407B30EE1ADC1440AC2D57A8DAA4FE16813AB58AFAED65" - }, - { - "key_seed": "18039C5E631E718706E5E4D16E9743774C3CA224827B14B831DBF73E3B0BB89D", - "ldt_key": "FC4544B4C389D90E145ED6FB0AF7B65598A72305EB6CDE719E50998A54846487794B7AB83E065A488EEF049FFBC173BA3C46FE61D41B8C5D1B8FE8D95369D691", - "hmac_key": "26A5EE999C16AEE67BFB7D0C99CA798A7C336210A464D3873F81A194ED7E6EA7", - "adv_salt": "09BF", - "plaintext": "642530D92AEE6E1FFB643141611A54063799B2B2FA3BB0612749E11C1ED2", - "ciphertext": "6862DC411093C22159CD52C078892BE2B44DDD51CA80271D3AA86FD9015F", - "metadata_key_hmac": "D83621ADCB72B4868FC98888436BBC1CB298B8189196062D8C5481A1D0C36144" - }, - { - "key_seed": "07E84066C58C06C51EC8B808170FE789532CBA93C6582D0E754BE6B22B14FE71", - "ldt_key": "A31BF22254E1AD18C8EF1D435BA3943568E9E5D20BDC4D4679F34CDDF0931DEA62871B0F8560AFD4EEDB81680720EB3687D8807BB621251743415DCEB387CC10", - "hmac_key": "9526730144BEE056A80AC643CEEA02CC05ADA715948BC5D9FBAFE7CE57A241F6", - "adv_salt": "45DC", - "plaintext": "049476A522B205FA1A4FFA1D11B72371188596BCF23675EF339B", - "ciphertext": "DC896B566CC1F42ADD142657DE80FCFB22120F7C5A38564E3F3A", - "metadata_key_hmac": "E863A720661C1E596D0DCFAEF4E606B5EAAE99AE7C1435EF2705A5819D0542C1" - }, - { - "key_seed": "3129749A31A2D287D0847A668253135CD00CF0313F65256BAAA0982B0916742A", - "ldt_key": "8B8CE49C6467A653BFDA93865DE10B97D5618843E5107B7A416B4B841150A45356950A78DAD9773C40A7F342B341A04514EE6F37BC822D69915D01D423D863CF", - "hmac_key": "1C4D6B48E9E6FE68ED0B83EDF0AC11B1844C8EFAD0841FC6066BA8180F1FE42F", - "adv_salt": "BA10", - "plaintext": "F1FFEE839C1ED6B21262C0DB7408BB26BA", - "ciphertext": "8CEE4E47ADF425F010C2C5FA8FBCD33E2E", - "metadata_key_hmac": "0309251E455622EAA04B5E54736068A8A1940C868788FAC2C205A1209A8277FD" - }, - { - "key_seed": "9FA2A639EAA55D338CEA530C924BD191A1CC99CF727E9427EE59E291F679FFFA", - "ldt_key": "6EB3C48821C6FDB8ABAD5B676CA872912CEE0DC934B0012841D0738C5F1D751E1FD9FF27903C48BB6B1495D62A0109DA5BA1D594AF894CDC93FFEE5E7DF9C36B", - "hmac_key": "7410489E590776BC309BA2C538835F0A7138C46881074FE3D89A0A34B8DD964B", - "adv_salt": "0E73", - "plaintext": "D9B608B87689E69393CBA7045CBA2675D5210FD650E8967A1200", - "ciphertext": "395248FEC028BEE9FC2E94F0A7DCF1DDB14C0D9160F93B27BF44", - "metadata_key_hmac": "F880F33851F564CE5FE2D9C99CC3E75FBA95A52BB44755D6F99B8B00FD9ACC8D" - }, - { - "key_seed": "EFB1AA2A2F7D37EAAA53416A15B0F595C1B1785700C33685E30B3BA08E409C6E", - "ldt_key": "2DF7BA528C2E07FCE74117A645D060CEE32F2734E1012CA4CD57E2B97F7B5C168D70060296B2FA47B664E040CD7ECF4590058503D3D24967AE0CE9FC6901B72D", - "hmac_key": "36D64D8224129E300781C7256A05956BC61F6488C2966DB79D75E50F02E22DBA", - "adv_salt": "F5FB", - "plaintext": "CD7050E3B6568748C6D3B1141651EE8FFB74C58D67", - "ciphertext": "DFCA49BB63A411FEACB0582A548E80C9AE030DDA58", - "metadata_key_hmac": "329A9CF2F51A7F8518F19CB80E3DB6C2157D8F4BADBD466C3510196D91F02F85" - }, - { - "key_seed": "ABC26C4EDC9AD2E8414156FFDBE43DA525724F9C5340E0849F8D884CB52A76E6", - "ldt_key": "218CE9DFDF7D36F52A79A69D06934526E2FB1B23F8F4A2BB3191270B65642D9D81F959533DF0DC10D9D9D5DA482B2AC6E648662A15A38A5D7E551D791C8854A8", - "hmac_key": "694AC6E4B3626FDE141A592D658D917C53CE135A83DE39A7308C6AAF5D800F4E", - "adv_salt": "CECE", - "plaintext": "400F3055B755F217E37B1BDA6B9223199833B8384921", - "ciphertext": "86D1030F1E356691F1FF69B5E11EE37A7857F540B482", - "metadata_key_hmac": "7AF560570537967A5110F475B8AF8D085E452523EFB58E2C5665B109527CF752" - }, - { - "key_seed": "27AC86A165B6C6170123EB80412BFAC95B4F14718F7C8B73F0EF84140386A9FB", - "ldt_key": "B23836E5CD10B4AFF120E576F51827952492634C12E8D8ACD63B3173EB2B2554CFB9A2879E9ABE990386064FAE52C6AFA4C5A62AB6B7A3907791C962AD458A5D", - "hmac_key": "C17707BA5D666817C2C95164E5B048AC816E65961ABB53A2709937E3032133D9", - "adv_salt": "F5FD", - "plaintext": "0F0B5BEEAF33D297A944115A4D1C06FA2FE6E3379A", - "ciphertext": "B729C506A6F6DF9C07EF46E4A29164E9B6A1D03936", - "metadata_key_hmac": "31DDD00AB86582E2664500B7B76A1797895A508341B9BBC20A20AE3FF72ADC44" - }, - { - "key_seed": "F578B69AF49988BF7C2FDDB5C70C65A99BBFDF435D76E195934CEAA6A7D9E724", - "ldt_key": "D627666F52B99ECAA3A7CE145F1DA0FEE74EA601B263A64E5336A3307EEAD2D6CDC241DB163EA08B70A0B3E6C0DDDD846CD5925A0087B897E96E1477E937CA78", - "hmac_key": "7ADF86C014B307C4C76D6AA545F34C885CBE45586CCCA91BA444D9D839EA0657", - "adv_salt": "822B", - "plaintext": "05D4E637910F7636BDAF10C91C8EF92B1D0E6169", - "ciphertext": "43C0010F5154A64828D869C1E8D78AA43C6CD6D3", - "metadata_key_hmac": "99BC82BC668CF625E2AE0C57BD87A5EE34DD6C4DB06B47D64DC734CAE3C51FC5" - }, - { - "key_seed": "7F5230AB4FFE1F84F9CE47EB0552A7C3EF609D1022A8A63948882F4C01535229", - "ldt_key": "FC342ACD336EE593AB577321825B3692D1D3D0784DEBBAC1F4FA23C98C5523AB04203F86122BB874987062DF9F94F91B875C2FC505998D07779349C7811BB475", - "hmac_key": "D62D38D7E3DBC68343AF3053E872AA59D2AB568627ED9DBFB84E1A5D29443F0F", - "adv_salt": "403E", - "plaintext": "C57CA7E2F5136CA9604C96D8EDA58DF09E78E58087A5B07838", - "ciphertext": "C330D4F9C93587A1CD30B269654FB34C113D4AA0254E7137A7", - "metadata_key_hmac": "AE6B59CCEB9EAC49D550FC756FBE278215C92CA503D72AFC6BD5D7887B5D4868" - }, - { - "key_seed": "417D441008248EA41F90273D48874CF56A9DAC55270F5959E210D28D77AB0857", - "ldt_key": "2C28EFF0F105DF2ABB5EF097A1DD3B7266582761AE4BA1413A3C1C05203CF08E5D9A69AD9C7F0DAEE94BFEDACB926F0F6E6C1C460B3257FDE29E53FA637FA3AB", - "hmac_key": "773DEF77549B95A210F4CEDE4A0DA2D819A1A744B1BD7DA83321199DD11FAD62", - "adv_salt": "CAEA", - "plaintext": "0AC0691AF4BB582180C62183B345B241F6F1", - "ciphertext": "A6841FB64E1F975B1E33AC1115BEA5C54731", - "metadata_key_hmac": "4EB36FEB8FC7D5B3C1594FAA66837FE74CAB1EAB5805B40C68134CF96BDA8D91" - }, - { - "key_seed": "D8BE2DEB66079C2A189BDBA5ACDA0CE82C52E804513CCD7458789E38BA81CB06", - "ldt_key": "64EAFA3B3394895597807680DB7F1B8AC7172495375C0547577415110C8B021902C6A31AAE1D288594D0BD59396072877633DB1F3A794DC9F9549609CAB703E9", - "hmac_key": "7B74179C3AA756E8A538CC1692F943CFB6FDCC89C7B39715042DD210D8333580", - "adv_salt": "4073", - "plaintext": "B7E33A6E31B663ED161FE93A7094BB3A6A", - "ciphertext": "B57378C629B1C32A257E6686E8DF988F8A", - "metadata_key_hmac": "02DF9779CA339B433AB29E36E81DF868CA95BEA952ADF8E2E07240CD63783510" - }, - { - "key_seed": "6EA44D999C40873243BE45A05C3B9018F4001829341067BC146F4DEE92DEF40F", - "ldt_key": "34B9DF4B38CC3D8092B944C1A53FA957F0D655250113BFC82E94E06B2F1631EC9EFCB8AF36038B6289DB7D5EEF67BA75EF358007D3F6A1B0B2BA0C836326E6E5", - "hmac_key": "ECF156444A6B6DF4206076E4B90CEE5A6F97151271F866B7947B2B816D8BBE33", - "adv_salt": "8130", - "plaintext": "EF938897F1CE69ACF8682432D676D657C03A49754489B0", - "ciphertext": "E788FCF88F97736EBF9FF8B33A3D05698709C053977EA3", - "metadata_key_hmac": "A24356616C577C504CD564ED753E73F513F770175265DA809C90DD8C98B60766" - }, - { - "key_seed": "B5FC1961F611B50A2A9953E7C36D271D08220FEB4986421A2549AB1100418F5E", - "ldt_key": "A8E12CBF2C0BAE68EBFED064BBE586247ABD2116CB5289E6E98D2B2ACE1FD48109B9877081766330136895F1FD6F585FBE3F5F0EE36E8D4F4DB64511266EC732", - "hmac_key": "851E5CDA65FCF29727A9E964D35A65AB682D2E05858C25FF70428719BB572531", - "adv_salt": "D8E9", - "plaintext": "8E1698000B95B7B6FAC61F5DB07049F00EC8D652304E94EA", - "ciphertext": "E5ECC2FDB01C052E5A666A131F160B263FA48A2B2725B56C", - "metadata_key_hmac": "3C54F7FB95594654F7EF39804C9CE54CE390A862C24921781B6ABAF34E960A20" - }, - { - "key_seed": "FF14DC92A2C83279AA4E8D766C754026842A66A881E03C11A56D25ED84C1BEC3", - "ldt_key": "690D6F6D509994CA4949FB7ABC137B34B1BE1FE69DE6730632009DDAE117E345A693D3A579F781D1542CFE2F09C03D6FE5444B5408D612C38A3FC9636E39030B", - "hmac_key": "B79E2E333CAE27B5B2082ABE06F9CC314EB1A6D6D5D2EF70CF63E4B7E30C579D", - "adv_salt": "31D7", - "plaintext": "54A39E955424818A57DD2805AEC1498E4AEAFCB811F7674DD8A6", - "ciphertext": "88D16368537C2BC70D734AFB07323AAF37D51E3995BEB444FCC4", - "metadata_key_hmac": "0B77F68966ED8A0E76893CF64C90BE597268F8FB56412027D2BD7B765FC87BBE" - }, - { - "key_seed": "C4473B2E6E2F31C7736B118AB5D9626B78CAFAB5480C64FEF40F6EA23DBE7A3C", - "ldt_key": "C657825718A2C746EE1C90C18A2CE9B6991C634A1C5828BD45510B8A6BFEF7F204EF2EC7C1402C5193F94691F0D2B2FAD84BB4BACCA761C72B1874E289210B44", - "hmac_key": "96BEC806C7FC3EEA8B19C179DED4A2EB226B1E8B3385066CFD24FD9A837BDEDF", - "adv_salt": "FF46", - "plaintext": "A3841B00F0220E916B5ACB7A71EBC7B833108A66618304201F22C7AADA", - "ciphertext": "9E0960626A61097A1C4AAF5BCC94B90898FC14D8B51FE0617E4B6BE251", - "metadata_key_hmac": "53E4FBC415ACFB8FD438618F6D815B6A8DE77344922DED695FA12BBC9B5FA44B" - }, - { - "key_seed": "474FECC88AEC0CFFD59038B1E48667A15F1983EED00388BA3321B78EA28758AB", - "ldt_key": "9EAA8D17CC67A89956041175D5171BB0DFF028C5E8416BF6E822DB5BA09E2BF20A45811DF8001CA0214523292EF22370C91957CD8A5EC05F5103730AA13E1CBD", - "hmac_key": "FEEE6A7BCD8411A7FB71A8EEDBE9CD0684C44AF977A93807878D340A001DFCFD", - "adv_salt": "0C48", - "plaintext": "9B1EBA3BD9AD1F7958C66E906C8DB21F5AAD8E358075", - "ciphertext": "D50230DF83D87F0CE0F37B41DAF6AAEFB1C6441E270F", - "metadata_key_hmac": "A2F7759E8193B3AB8EF0D76BBFCAA514C9C6096E81FD497C08DB5098642A4CF3" - }, - { - "key_seed": "6FDBEF4C15EAEFF76DBF6458FD5B6C15D6A1CE68348B0CBD7820AEED7E9A4E35", - "ldt_key": "DB7EDA05A1DB8DA743EA148B1A6F0EDD0130D966881DBDF830581DE9F5222E78C7459F0D3C3A0E9D73F1038B6D23BDD7D64BCE352F3FF2FE115AE5E65F31729E", - "hmac_key": "2E60F73C97AEDCE38C36582822BDAABB612D79845F7724B0BA576E2DBEB8A2B2", - "adv_salt": "E99F", - "plaintext": "D60F851EC8897A4B8DACA7DEFCE0E4152EFA9C54", - "ciphertext": "2E16D4480367179CCF871E14E38CBF2FA2171134", - "metadata_key_hmac": "B8BDD63EDB687A7B8EC7B8BC8967A799735AECD7E95553B6D32D46973177D3E4" - }, - { - "key_seed": "F516557262D28E66F09960BFE8564A8E1CADC43DBAE7CB0E82C18B2BB004ABAC", - "ldt_key": "7CD3494F9870628BFED5FFEC6E621C94B7A1ED4BEAC89C64168CFD3B7110A36F2E0B3CFA1C2C33644859514B17C5DBC7254E177ED5B4D4BB5526355C84EBFBB0", - "hmac_key": "5396B5EB45B5BC6E30BD4F1D7D692ADD9CE70418C8B4C5C3B2194E1BB3327E89", - "adv_salt": "C01A", - "plaintext": "F002C1693EECC0C20F773241EB3FB3C4", - "ciphertext": "BFD413373158A3D367C73937E9737405", - "metadata_key_hmac": "9F5F641CB02A81FE6D997A87762E663352988DD1A09A093AD2CE61C0C25AE325" - }, - { - "key_seed": "1985D7F9F9A11F655B3C3EB9A81B9E90A1C959CC1427CBFD618316903A51DAD7", - "ldt_key": "A73191FC81DB46662B43A789A685AAA43390AE39CEB11C0C76D43F2E6B6BFF0DB177736F004010561FEE902400904A5315A28402CD7444AABCDC82581822BD14", - "hmac_key": "F44B2E47D31D57FE69C622110D03ECA496B3AAA6D69A590495A6B905130E5244", - "adv_salt": "85E1", - "plaintext": "465B4E165C848033E2E2EC74831ACB11B9EF", - "ciphertext": "E135AC0571809DFA95E34512560A06BE1947", - "metadata_key_hmac": "DF267B79E8A22CD628EA16C01A64D93603C900D2B388E581340042FEFF746B19" - }, - { - "key_seed": "9AF3762CC76A2A6203862DE8D2FA67CA0A73C01075039185177DF0414D56D421", - "ldt_key": "4764968DD0942D35868079E0AD4A1BA71C8BDC5D256E60C8E57AD84238BAFCD2277C80BC1EDF683C7BD26149680314A79FC319FBB4D90F1537AE421155C98B71", - "hmac_key": "EA15DB5934168ABC0623D13E74AA98097BE49679B953CECBE96A50D02AF9ECBB", - "adv_salt": "89A6", - "plaintext": "B134F7F24998FF5D1AC5A2815B0EA229", - "ciphertext": "53A50DD852AD8110D429CEAF2FB3EC97", - "metadata_key_hmac": "C69C88641A083EDD5659788CDD5D3A097E12A687200B84899D8681A8F7678653" - }, - { - "key_seed": "76FE0B927C490E294DA486F85AF5DA0EF5CBD230BA8652BF3271AD0E8800B5D7", - "ldt_key": "CE41FDAFEC4492D121A51419118BB84B2ED584C4AC5F8FB0FEAFD6C89C8E293D74B1241C99F53994254753751F486F013BACAEBA763C7FA90E4AEEC759A540AB", - "hmac_key": "64A57BDF04F5C58FCC5BD089DF52327FB4BA704C1340E9DA91E2AA8C81F33D6A", - "adv_salt": "4A90", - "plaintext": "E29B0C659BD28FAD0E037818E6A8932799C2276C6E114F5F7DA2", - "ciphertext": "99DB117C981C745A22C8E2650F5A900E2FA9C97E65511F1D9E23", - "metadata_key_hmac": "3C362A974C82E7449CC0FC9DBA40A324879F98E6CF7BA38CA3698F27BDDFD426" - }, - { - "key_seed": "9DCA3F0D2FFC32BD5C68951801F3557549E1AAF83A21679C2E6C40EAA0DBF6D2", - "ldt_key": "56ECF11E51221557A982192A8F5A3D36F5C29A536FC878DDFE470EBA0BE41C53C7B8817C24EF68EE70017D76EA7E44455438FB14BAE69B224ADDD6A3FDC306AC", - "hmac_key": "3B9A4A380E58FAB2442761DC37F6F59DF05CDFAF09422CB48FFAA6383C6F3361", - "adv_salt": "A4A6", - "plaintext": "CB6409DC49FF98448C088D4A85CDD6DAFE00C9", - "ciphertext": "613B69F24FBFF245023185D0910147158051B4", - "metadata_key_hmac": "648100F3DC460E5ACF5B55EA93724C3A6171C7AB188D9A90335E1A28D96BC43C" - }, - { - "key_seed": "25B06DB454B451879690D09CA4ED02860760E1CDCBEE695A61A2B81C3F386C31", - "ldt_key": "A3CD706DFFCDB4B801D147E9742833947FE9595A75A411DB407EBE5CAA84CC669001725060D6C29F50004242DBB49E13A14DBC79662E253943CC1AEAB6612297", - "hmac_key": "367818C87FBEEDA9AF02EDDF6794A4FBEB24FD1889AEDA80614AAAFDA0F39E0D", - "adv_salt": "B7FF", - "plaintext": "91D4E70BA0BA41B5168A89BC88C7BA1A42D27EDF4AECDEB29E", - "ciphertext": "CC6376D78FCD2AAB7F2B3C288BDAE96938C69BA2E17E82C7A6", - "metadata_key_hmac": "EE553F38B53CEFEA846416F90466FCC2C828FC549AC0CA22EDBCCB3664B58EC0" - }, - { - "key_seed": "1A9E7CF67D957D6C95C4911B7F13B51B03EC8E32A6452E8AE0F5CB5C237A9F58", - "ldt_key": "F0628474832A206D611FF26047B9278C20F051B814C304ECC3C965C9304E8899105C85C2F8AFB290E0331B884D2CD6E7F4383CFC2214810B3DD83BBF58E6EF58", - "hmac_key": "A0DF5EF1724CB80A2486FA2B145535EF01451A42AA5A62F10DBCE6C55DA055F7", - "adv_salt": "54BE", - "plaintext": "26C389453C0A3456D8D18CDAF04CAD2FD8BB3A0D2528113A3BD0", - "ciphertext": "1C1540CB04BC79693A9FA3CB3B9E8B4BF415BB327D92641E7204", - "metadata_key_hmac": "E52635CEE4261B063C3D8C0DF1C0A0F040CF72464DF03924051533BFDBC3C1DA" - }, - { - "key_seed": "DFDACBEA9B418D02783890D8A66D81061C9F1F09B7B0E5FB11D9C7F9AF35F4AD", - "ldt_key": "DCC6C3DBD5EF8F7AEB877DA03BDD7DC945063E79A5280C5CD8EA518721EF2A4AECE83076F17A6B38EAADA6987E3C556B3AD1FB7D8E9BFBF63A2AA84A06AE59DB", - "hmac_key": "73E4E1ACD47A14115E5611804F7FD90B014DB454049FA6D5257B0B2F96292046", - "adv_salt": "642E", - "plaintext": "C3462E884C31AA6FBBAE14F8122B770F8EFE2CBB268026B283", - "ciphertext": "E2FF6E14DC25671EDE98BE654CAAEC991D52F34DB57A7662E4", - "metadata_key_hmac": "1D1F7DA5CE37C71C6FE067FCF8FD3BFCAC432F9B2F2D06C0F5E62483F9F1D0C8" - }, - { - "key_seed": "5FC38477B52B0DF63A72767E8C7F84486589B37F310E1C81D6AB646C557BE94B", - "ldt_key": "26313C24B59A94E324988C760095C13AB03A75CB3410E047530177E9C999B76160D699814FA4CB9D800962B25805CA910EA3870A5347230382A2069DA5B87A77", - "hmac_key": "59ECEF5646AF89D199016B71BA556742CC361C3535E1B076818E474CEFEC306A", - "adv_salt": "0683", - "plaintext": "53FFDF24B36D08AD8BC90CCE772ED7167116F2AAF3375C87", - "ciphertext": "FB2B693185BDFB21DBD3BCEBDE0C88D057C8058500D2258A", - "metadata_key_hmac": "39578AEBEF9134108001199C0F5D99EB698986B2546A514EB95021E9F545124E" - }, - { - "key_seed": "7BC0109CCCF62E83C50895C7E43A4E571DAA7AE8E65DB1D1EC6B3D0933A71AAC", - "ldt_key": "13F3CB016E1B394DDC3FC5EFF350773995EB6141F9CE4990C908817B901BED2BFCD9729D3B798929B23FF752F256505315AA79F2284E6A1B07554BAB192A9654", - "hmac_key": "84A6B032A7FDAAE377AC1FAF708107D765FEA8F9A050D8F8A412A6E2F3F08D87", - "adv_salt": "29BC", - "plaintext": "7A2F9C221913A54540F9386C20594B8B807C0B411DFD", - "ciphertext": "551EBD847E4F22D868AD37F1694AB7D5FF0A0114A4C6", - "metadata_key_hmac": "7ED99D0E49848BBC2A423E5ED9C3DAA1C29F1A9222A2FCE31FE19133214781C6" - }, - { - "key_seed": "6556168FF9D91B457BBFBE45618C6066EE1173ACF423277876D0803764B378A1", - "ldt_key": "F6346C417BAEB4E4B83205503F81995AF980B546725B5AF8BEF3D66E7BDDC4C9D10C9E6274B2BC37F245D32BE9816494575D33735D0E977FC0D808589DEC51C7", - "hmac_key": "B685C810EF6A30FCEFC6B94560CD351586D534C98822A48882411B01D77AFFE2", - "adv_salt": "2EC6", - "plaintext": "AD9B7773A268252FB51D78FA76D1CB67A116FEF859", - "ciphertext": "0326A51220BC1AA9AC4CA940383EDA8F52F7EF9B68", - "metadata_key_hmac": "8D417A9AFF37F839EBA324B565BAEF9A46E8313ACFEF69B286E5D61F189DB28B" - }, - { - "key_seed": "F6D1B4EB6C21BC252E825A854DABBC246E330428BB06FC8DF5EFC0F5B5889389", - "ldt_key": "0B96F3063EC9E34A6BDF15AE7B674815B5B17F56ACD7EFF47DA2A5AE7D689154BF4E59955A1A79CE2F456286839CDFDD14B4A0EFC1C2BD3460DB8315E3C40D6D", - "hmac_key": "368E36531A75F11087698461D3615845EA409507B6C9A119B6D50D632F6D7BC8", - "adv_salt": "CF7A", - "plaintext": "9C4125F3175168B367DD6EA3538D9D9EFA41", - "ciphertext": "5E890D2CD7595B8171E7C50CFA3097E69C5B", - "metadata_key_hmac": "7171FB1B8F2158A50DA45A423A42BB72E3233F3D8C808D8D0C6DC2E1E2D6895E" - }, - { - "key_seed": "F6C5D8E0D76A826F04E4DAFE0AACB059BB5940CDCACBFD101FEAA4172A140AA3", - "ldt_key": "D790D1A0D421EF9031D83033B2A6C7A1C6AFD7AE0EA9B9900BD6BF74E7038CDC5A36FB04548C2C833F3458E4D773092356A1053184C0A10B67143713A1208F06", - "hmac_key": "12C5A42D2BE721E5BCD7A5C374EC4789720DF2D5A6B71157D2D2E6D23661CFEB", - "adv_salt": "34AE", - "plaintext": "50FA211D4BADCFD3E6965500B45BD4EECC2E8874EF45FAAA8938E7BF", - "ciphertext": "BDDB582623B1B58C597D42F549CF3640261A5D6FBE88C5A2AC2FFD5E", - "metadata_key_hmac": "BF2C041FB3CCE7A04AF3425E6ADFBA23E30543C7C1D928028652FDF6F2DDACAF" - }, - { - "key_seed": "10285759BBA3CB207EC111088EBC49D081092DE814F1C9D890E11963475BE0A3", - "ldt_key": "B1A6F6EFBB88624AACF468774C77389B97A49D93481338B11D679A3F1702937EB044BA5421D81EB2027489DD73DA13E45B10FE29792E7F9530AE06DD332AE0DC", - "hmac_key": "361C19E2B28C569B81E998F28D0CB80FF5BC914737FD335A045F5CA01C721C80", - "adv_salt": "5EEF", - "plaintext": "218A25CAE4B4D5BA6C12641906C9AB50A51D2323E71B2D9B464D43B5", - "ciphertext": "2F934A6E4466228DF0F4D652F95E5650A4B9B9789CA4D78B949B7919", - "metadata_key_hmac": "9AF6B6E76D98AEFF48249DAD198B2358512A10C8C2EFF566120FEF2429DE3955" - }, - { - "key_seed": "220BA7962D605685F38568E09EA5098A19AB872E170583F910379EE94CA6DA1A", - "ldt_key": "93F036E1B7F015A73B47F8E6C16AAC1D5C6BC179FE6759C453BADF5367F0619A6FB1025FE0CDBA7745FE83492D345AE5024431EEA1EED8218D1E960B54CB4278", - "hmac_key": "17FE7160E653F4E0FA0F09DD66AAD32CBCD9F9F6BF83E2CE40A99428079ABADA", - "adv_salt": "8110", - "plaintext": "4CB2A60F7C9A1B845D1680C8B9375C51E6CB44E61886A3D0306F", - "ciphertext": "7FBEE40B608D1D7052CF17B65323050FB0DE90DF6B38A8DA5EB5", - "metadata_key_hmac": "59F2040D895282A92F6531596BD351A41E717D5CA1764C8CCEA8983E905D0708" - }, - { - "key_seed": "DE213CB6D5B8B7129DAA8E26E27E6A0CB1930A01CDF9704F575DBD76413EAFAE", - "ldt_key": "27B7F2836600D37B972D9A27280B42FCDC15CB731FA1F4B3A3F0C374E5E4AA9AB5FC246BBDE00F768A8CD5E304B80297A20EF9DD499531B3E2C2CDED0D540FAF", - "hmac_key": "BC34959C3219C01512CDDD44C862CC9F011AC0F23C3B272224FF02724EA07D52", - "adv_salt": "8B44", - "plaintext": "9B24865ECD76F202D8153F696C04C1879B1E3784D6D49E972CBB3A", - "ciphertext": "9BCEB06CE8AB8F2E72FAC2966B523640C37D76DB2B2F16AEFD0F8D", - "metadata_key_hmac": "94FC4163DCD7FF3EBA6856784E89A291862F204A7D08E6C32F9B4E6DB6BB1DDA" - }, - { - "key_seed": "0ECD554A2A723FE725CFC2705C80CEC856C0DE19FB6BD7538699B3C24DAA0E58", - "ldt_key": "FC21A6BCBEADABB421C2CD1050D49D6CB3B7CAA2948E08948236624DEB01C84DAFFB364E6FCED0D97A554697EAD8F1F9B10B691240E874D123C6090EF591B14D", - "hmac_key": "F77F5C04535B91E72F42C2FBB9119D11F725485C89CD00101B54C11620B1D859", - "adv_salt": "6C04", - "plaintext": "72D73F9B2B97C231B84767F800F208F40FEE06B86872543908BE2C", - "ciphertext": "756D7C6D7430162D032730E90CB7C5EF67E512943835BC96511406", - "metadata_key_hmac": "8DBAC803E7B33983AA84C8B4E46C6166DB7EC8FB9945C42B322FE3EF5293BC25" - }, - { - "key_seed": "D7C8847C7E8FEB4DC442983177006DA3175CA0BFCE52F0D985F96031533252C7", - "ldt_key": "BEE93D5D4B768CEA9B85A7E8CCC16FE5E00DD641CC5B705D87B45460B2D6D5AEC3772808DF95BD3711C3B5820674B30F953FF79F90F5CBC5228412CEEFDFD381", - "hmac_key": "9FD237BDAC010B287790CFEE3E8B68D398155C7F0949160E0E93AD7A36F647CC", - "adv_salt": "9A38", - "plaintext": "8E559E7BF8732B31D60C3EFA73223EAB696FF05FCE0B2B0DC0FC9ECCC374", - "ciphertext": "165A73C30278CA40D354FCA5B7FA2F59B03C8C210034081C2DDC18FBE930", - "metadata_key_hmac": "95EFBA62585B0118AAFAF540AD9BB9D6BE0132D5156307BA67B1FFB0BBDC107D" - }, - { - "key_seed": "B00C7848F767F1FBB5A0225C372BD51669265000F7EBA2A9D625D067DC1EAD7A", - "ldt_key": "7EA6F36DB004694034425D297C579A7DCC33D6729B139E77461E65C774A94120FFD58EE9D9CD0044CE0BB288C3B2793323DD7EA112ECAACD788B44E28080D70E", - "hmac_key": "ECE14011D70AA79E61490480DB5AB1C5ACB53EDE41A50A5A225D6F90E2C74521", - "adv_salt": "4E1B", - "plaintext": "BC2DBA155EEDED7C96977A0B0CF5FBBC79", - "ciphertext": "78C1642FE8C19833B2E7AED931A293B292", - "metadata_key_hmac": "F7B56B39CB7C6B3F9D3F2AE89EF989E2F664A1C25D2731429CC27B21EA59EA56" - }, - { - "key_seed": "EFF15E04EDB3E9CBFD83EAE7F382157FF3530FD7E3F8D8A54A0A363C9C6470FD", - "ldt_key": "DA2189DCD00721E778F6AB10606D850FAF706A5559ADE0A42325AACCA290C70AB6B33BA9EC9E306EB05ED7C663112D269ECF3826829C1065E81C66ECDF583AB2", - "hmac_key": "BB5F27D52B36BE2D25C86852447F4DC8C2E2DF177A09C824A06C1AC5B88CABB1", - "adv_salt": "A192", - "plaintext": "5E87F5E0390DAA539CB23D30FA108B5E5E", - "ciphertext": "81B198280231AE878252645A008ABF41E6", - "metadata_key_hmac": "8E0FCDF5A803ED0A0FE5C9AD1AC804021AB639DA0A9FEB446AC92C574C42C65E" - }, - { - "key_seed": "7A5B7C7EEF6FC42ECF811708D4CC50937D1E8E34A0731872300A7A345A401DF4", - "ldt_key": "8684BDD009C393BB0D75BAE4DFEE01678E0C47E637280DA920A07C2AC22180145DE8B6417635014852252BCEC39541C16B61D7A35626313DD3AE55F700959E0C", - "hmac_key": "9BE6EF13D2F5DF52362C5BFB12EF09100F8813389F67E52C667C20FEB919EB7B", - "adv_salt": "A942", - "plaintext": "F27F913224CD9BC58030F048018DA4B3667B57CD1CC1ECF458A927F5D0", - "ciphertext": "7B99EB504853A634337AA496326F73DDEF2D3ECB167CF63296978086EB", - "metadata_key_hmac": "3D3BE659C937DFDB2C6A4F46F9442C598E0D9B40E157AA13DB32173ACF3DB2C7" - }, - { - "key_seed": "5553AAD088C78EDE5E514B5E26661460D80D08E01FEF68B405B739563FDE1EB6", - "ldt_key": "2A5057B7BCFB1B7C0CAA2EA015D4E12FD89265FFF6CE3823646A00C7A08935DF5E5A29840BD122F63F63C18A797B3E9602335DB08359CE05D77F2FB6C57380BC", - "hmac_key": "75DFEC14AAA30E575AD765878A7C176A6BDBB4161BCF290C9E43C7318BF22995", - "adv_salt": "EADE", - "plaintext": "5365B2E71530B9C234A892168628B7DC9B311EEF7C1BB4DA30", - "ciphertext": "C51ADD62C74475554288701418DD7D452EE98DE6167DE974E9", - "metadata_key_hmac": "C01B4C26909491F1F5CCE36C1F1C1B2D9D016D0733A03A4665FD8199C77832A3" - }, - { - "key_seed": "342998189AAC53997615C11612B54678E8E9473130526C8D5CA96DEB4FD09952", - "ldt_key": "90D25EE1ECF1583D205C967D9261ABF68992DE0D764F839B146DA4F4D602BA585E41BB6BE6D5B2E9E84B1D55A99D54199DB03F46658C29D7721745F49BC0659E", - "hmac_key": "8DE8826FA0A83FEB3021CED9328AC6A0C524359315C07DA092A348B75689A693", - "adv_salt": "978A", - "plaintext": "57100E74E9354591C38865EE216BD6F484", - "ciphertext": "AB4AFBD82E5DCEC98D78F2860778ED9F59", - "metadata_key_hmac": "A796997AFA2C79726C851F15DA52F09018094BFCA62DE9BEF97459B291540D57" - }, - { - "key_seed": "9B1AE59DDBE239E528F9F5C55AFDCDB149EF23D969139E7862DC7D218770DEF9", - "ldt_key": "9304F19DD2FBC4F32A385354B194D7D218CBCF179969BD90D16765ED59C71B6D38D972747455A19D148C6EE16029AF512338AFC484189774FC95951610A78C81", - "hmac_key": "8DA66E56659443CF2E7B91DAE76CB36FFD42CBBB10ED13B210E86574FE19497A", - "adv_salt": "CE3D", - "plaintext": "66F3A9EBB3C43FC6CE838B75129B30A6F85665A4E9029582F91C18AF", - "ciphertext": "6EEF47363208CD36D82B6602061296A397DA03CD733BDDE5E9DE1F00", - "metadata_key_hmac": "1DD6B7C062D32E173D8CA2E67F67582961852179ED024C40987B5254D7A50E95" - }, - { - "key_seed": "5A0477CBE783AC090752F8394AB04DCDB79D999E1FEED9E5695172A345BC541D", - "ldt_key": "C6C3F4BDD7B4A036F7953DFBC3ECC22CBB8C55426AB21AFEB6CA45965663482EA97EDFA5A9045D3128726CD276054689A9CFB150C55953DDBE197D52442DB16A", - "hmac_key": "AB97F7D5A5C3205AB01FF7BDF493E2362974EFFF5A651EEF4F2ECBEEF18A0FC8", - "adv_salt": "61ED", - "plaintext": "EE7981B54E1C17379A9E232ADEF0AF0354FC7B49610F7430360385CB", - "ciphertext": "A6A5C88FE8864D61EEC83F47B2DC37F053BF2E5968DA36EAA7A187B3", - "metadata_key_hmac": "60193EA52A588B2E96B48771772318274A150485B12E4390A30F603612514DE6" - }, - { - "key_seed": "8378C9D73E14B679A3B3321F347D185ADCE9AA1824A1D9C0DA1089B6B663FF53", - "ldt_key": "F9D2090BB4CBC921E7AB7D7C37D9D988D53DA0562256353002E753E28FE473DDD7327EF546EEC5BC81E32C6F074DC21E9B901BA23A2B1B66CFFA12452669EBBF", - "hmac_key": "E7099C86A931996822238596F0755FA6F9AD36AB1D79A56A7B1DF9A100ACEE66", - "adv_salt": "49AA", - "plaintext": "E7321E12D949C101CA8D7724C1C739068339EA83C6DF7FF23B6722", - "ciphertext": "DD266DE58B819279AA5B6DF6C815718FFD9F90B3CE1B41CE47FFBF", - "metadata_key_hmac": "895995674304845A63AD2FEBDB297E92756705A0A4AFBB6D63A8201FA9433419" - }, - { - "key_seed": "6519CD0C608E0C26F2BB415F84DB1C06E38040908C1AB1CBA3107BA723803102", - "ldt_key": "FCCC5250AC180FE5DFBC6367F20AD7D01D9093065264B9BDA4FEE93BD6FEDB4CF975AAA2370E26BC5BB45922DEB7D9F70C1774F3C99663C6C7361338750C93AD", - "hmac_key": "5B859752B379C6A0F6DCE584EA8D269EE0D05EA427D2273F477938202C21410D", - "adv_salt": "1BF7", - "plaintext": "B9B0E3752451B61EE55191B06F132CE2B820E6C2B7E3E6E79EF9381EBAE5E9", - "ciphertext": "5283C33EB405CE3C446F55009EE7C2B7437278AE93053E4A485802110D90F0", - "metadata_key_hmac": "1C3B91B68D6D3877942FE09D81FE14B8194E81DF9F5BE5D64DB48E5CC6483AD0" - }, - { - "key_seed": "3080ADB8C31C7E86F143516E7AF784F5C8384492484DAE622EF38165F1D616FA", - "ldt_key": "C315B24FB8D12074330B44B79E5D1A55AB2FCDF5DC657F94C668269EC6A1B438F43CB997F2EA99BBA7BCE882BB1599EEE2186FED20F3B2E9AC060900896D1FB9", - "hmac_key": "96C5CD3A6F2E1EF2F4E4E3343130D3D6E8DB4E42EF827A9F18EEC1CF3E55D4BD", - "adv_salt": "1A2F", - "plaintext": "E6FD8B3CA9C82B8D1D0BFA1442BA8426A821C6AF8498FCDE337A0C190CEDF0", - "ciphertext": "7431DC4FE965D7FF3F7E24C35B373AD9F0E62151C1C7F659660B3918E00D2F", - "metadata_key_hmac": "88B0C48D71E99C49B7D4E7DDDAE5055EB9A653335F3A9D0BB11B0654D18C7833" - }, - { - "key_seed": "D3328C7913B9871305EE82CB1F2C9041B870A2E13DDE9DB6875301A14053B417", - "ldt_key": "7DE72172FBEC90BC3B6D1EA3D8337C61CF4507761BB0AC07F65EC0E78F9FF0C5C31873F917146FFF7B0896E051B3BD91B9EE6BBF427D95457E5AE321480740EE", - "hmac_key": "FB780A0BDF5D9984E087F68F67EA5623ECF76CDDD01329A56DBCACCF26F73E40", - "adv_salt": "DCC1", - "plaintext": "A59B5F0D5EAF92089A1730DA4682A3496E54B64CBD9A807EAA3B", - "ciphertext": "AE664C161DB820537E64F09C548B69C3C092F636E21389307114", - "metadata_key_hmac": "A2BC9EC43EDC2D499A6880FE4F27625FF49D1A495B849EA708EEA92304229BFC" - }, - { - "key_seed": "2803E63904B8A4E5AFEDE903AE77E6962E2E299F5DF01BC6209419873523596F", - "ldt_key": "CCB93C500CD50E2F6CAB777CDF5394ECDA8EA693714846BBAE0E5E4A1C0E959146330C3E6CE82233768ADADEFBAAE9BE922CE2F5995335308B9D6A522A122FE4", - "hmac_key": "6175BFC44BA2CCFF262B01E1E20FF8968E53B355BF670DF9D2C22F3174DBFA98", - "adv_salt": "C73D", - "plaintext": "9014E2E9C22C6D9E1AF3241E6851B353850E390281F5483171", - "ciphertext": "A143626231C3DF6F08A1F7C0916F3DB97F7195DFACEB8E9728", - "metadata_key_hmac": "139205577C16628258160C63520323131D52C4979A308243EF2C6533C3E9ABE7" - }, - { - "key_seed": "C3D424CEE12CF6A80292FCC88963264DA1CF1D41F88C7B4CFB7F38A18BEC123C", - "ldt_key": "EB9ECB3EBFC49B2BF206542BF49583168756650160DD6416FB31BD31BDCA2EF5920E803DB5B07A51637AAAF6CEF151A7A14AFA201C9B5CF56BA645B1D8D19282", - "hmac_key": "23559CFA05E4ADE5389657DD8096ABDC8A790AF1CEBA0E17EF5A1F8D033FE6E3", - "adv_salt": "BBF9", - "plaintext": "B90FC627E9FFF36DB6A5C238504A501F8C247B41A433EBAB", - "ciphertext": "BCF8E38285A87704A542261EBCC3992C66CE39C52901103C", - "metadata_key_hmac": "80DA7A5ACB7DBDB8F107925C892D9C09F1E56296675637DDA3601A77764489A8" - }, - { - "key_seed": "B459A0BDAE3FABA1A0483CF35E2521751D24409F2216B1C74E5A19650F3A3949", - "ldt_key": "1C9FB660F68D61A43FDB5E8129C8C37ECF3DD5D0818FFBBC58C6E531C4810F4D49ED5D2143CB52C23328DD20A721EA8079A93CC3396EAA3AD2B70BC441182ACC", - "hmac_key": "F527F4313DADA66F7A003DF492947D52C0D54EE49FCF5FE48D5F8F5FBE9C1D78", - "adv_salt": "730A", - "plaintext": "EE2F0C9FB9B2D4DB8E0F531631FE8BCBFEB927F025", - "ciphertext": "442EB7DB8F4EA34CE86BD8CA8EA4C65D94E6E19F8D", - "metadata_key_hmac": "2599F8E42889630E883BBF901E5D531AB15EFBF13426B8913E07031673B7BE07" - }, - { - "key_seed": "49C0D2390E790C20FDC10E43CE517F7E3C8D41153C73A579C0EC74FD4C395941", - "ldt_key": "9BE90C02466954980B34A7D1DBF89EDA5095F2F68E917E0FA69F18FC62E74C25AD79B613F24C870B7CC368790E2877D8CBA2B747BB4F0678D615B58D6D5189E7", - "hmac_key": "87B2B86C8D1B86B3A4C01F6EACF91621ACA29AE73E4DF48CC7D7712C701CEE40", - "adv_salt": "EE34", - "plaintext": "950744D835729C77480148DD09D69EE20B162D8323", - "ciphertext": "F5955F45D7BDB42C320EC3795D52F2F72CF3B044BB", - "metadata_key_hmac": "C85280A1BF73031514C82D70CDBEBA53B415724FBEF00A8168745F2237128EAA" - }, - { - "key_seed": "0E7BCEFA797736D9F91BDB8293FF51A538D665CA79AF62AF4893EA83A2C600B9", - "ldt_key": "8D5A795EF8E36C6D7A943F3B171B98D5329796E1C2D535459744E85149D1D81151C19A04C5C38C2132A71F533CFF0DC5DE15F803A1AEF6FE1598534BF2A7B542", - "hmac_key": "53EB6926B56AE6EA948729B0196039EAD92AD9564A7D1F7FF31B4A4F5CDA35C9", - "adv_salt": "6A26", - "plaintext": "3E94D9314FD1E2BD2AC61C7CF03DD3EB5CC516B0679C", - "ciphertext": "6B6CFE9BB8345ACB4B6C7402EBAB6F10CF9D2C930033", - "metadata_key_hmac": "9A6F3EA0B48FADCE594AF0351DFD31859F9DE01BBEC53B38A6B4620D86195F73" - }, - { - "key_seed": "DC310BF157F0378144A7DEE76F5B95ADF3A7A754540BA7312553D81624AFA1B0", - "ldt_key": "44345912C50AC5A7C244ED31D7CF8FAB80590E4363AFB307255F0FAA5D40DC8A0E777E3B4BE153232F9E8F80355814933362C60F90A4D33368CB86E1665264AE", - "hmac_key": "A046F6ABE8E0DE35BDBF9B574E97A70CF0C61D98A731F81B68FA79B497602768", - "adv_salt": "342A", - "plaintext": "84195311841AC7F5544E44C7077F7F76E4", - "ciphertext": "9C3FD5C099447E92B60CADCF012E305008", - "metadata_key_hmac": "3212463C6B39DAD5EE0581870F9EC642E9D42CA5C70149149437857331152AE2" - }, - { - "key_seed": "8B7FAE7704B7EA2C6136FB5D18217490C65900008CE4317A75842613BF3A072D", - "ldt_key": "EFB0CA7F9009F3A9EC5776847A4DA88A70DBF28D16C6B7A2EC121C0F7F45E88EB238BD2481D21A675F97C0F0876F27FAB5BD5B1B7A69BA7A70F332F19BC3AA37", - "hmac_key": "821FB7E321CC7F3BE691AE146665D3AEE0BC78EF7230B0F1F6A3A59336C6C439", - "adv_salt": "C70B", - "plaintext": "778CEE9F3BA2EDFF226F4726628130293BB4", - "ciphertext": "5CA6A77F633C09055061928ABCEE07C9FE65", - "metadata_key_hmac": "8853181CDA041C90AD6ABFD39943FF206EE15D52D49A165968B0EBAE3F1E9949" - }, - { - "key_seed": "72ECBD3EC62AD51645F38FE2FCE9417602C5C0F9F0CA738A35C41BCC19EC9C5C", - "ldt_key": "67DDB32739578926E265C0C58FAE0A0DE3C790760C6DD1FABB8B5F24CD862A26B7AB84AC7847B65787339C444B432EB7525F73F2EB71108AA9F0363885BBD742", - "hmac_key": "72209D27956478D557A5A75E2F22D76152365FDDCD0608C5B79ABC0232F20856", - "adv_salt": "762E", - "plaintext": "247D04D1501578C3A2DF020E3738C224AB093577E2DC11F4EA2E", - "ciphertext": "4FC96DA6EE8388A22EDEA71A0B6E24B9BFF4E22092B13E02E187", - "metadata_key_hmac": "FBC931FE290F92097F690A02B11D69424C4325216AF2EA7A65168658FB371A1F" - }, - { - "key_seed": "2D6D2DFE7AE6EB7FCD45DC6F56A6CCFAA11F2C8AF5295606C715850F1271A5A3", - "ldt_key": "F8C3EDFBFD14F23CC84FCE85BF5CDCFF54403F25E936CBD3022E55C00EE27623DA0BDD8FA74BDA3278371073A4E72B54C3774E014A905BC5E98E58F884DF9240", - "hmac_key": "3985FE8E243BD65DB0AE4AAF3185E705B75AED530C02A20B45306AF640F34B01", - "adv_salt": "9433", - "plaintext": "267B1E7491E02C1A2CAAC5AD4B7F322CA63CAAB688", - "ciphertext": "28190D998D15F1D090EE151710DA6F0C7CEC7891A4", - "metadata_key_hmac": "B42BE1A6889A7C28348D831673BB02370B54115B7C67A0B5E374ED1E2BE38217" - }, - { - "key_seed": "9ED92E9E5DB3B44FB6567FF3C9C3458C4FC3121735035BF8E22E6E5A4D8666A3", - "ldt_key": "CE3ACFFCE7613342408FA6B3E77B1B87C820DB54D6A01DA651621F98BB4686D85D7DD6DA7D7A1B365D2AF53F35157F87273A4B27047EF7F23B38FE878FAF0012", - "hmac_key": "D262223CF5C87749958EF430B6E0A3740CB5FEBBA47B0946AADAAD739C344CEE", - "adv_salt": "9AF3", - "plaintext": "AFBFDB0819E093AB27853D2BA662D162DDD2C76115D29395BC34CC1D235661", - "ciphertext": "B702F556B5C400CF72DA68CF031FC048B609EE753549DCD0BBBF3A9870C2C7", - "metadata_key_hmac": "C775E00854CD584161F3CA8BEEB489C49CC3FCA7EB072C8007989A12F3EF0E6C" - }, - { - "key_seed": "29160E56B32F35828CBCB90039754D42E8A95514068C3760F8A63A4DCB32D030", - "ldt_key": "DFBBA94D4CA6CAC685ED90B8C11EE6BEABB2F508A0C3AF0A9DBA8505A24E9E97B1D5813A79AD5934C1E5030EEF56663A6F98D0E5B2E2F2E1DD9943DE7BC0B021", - "hmac_key": "1057562971FC6D0A0D2E07333530E41FFE50EBFB48119DB8A5C3F827464C2841", - "adv_salt": "5EE1", - "plaintext": "57867C339A963B8A5E271B3E8C3ED9C4D5FF42A9DA58A2", - "ciphertext": "D7747A26F1AFFF363FD8B27ADB19295DD633084D1303DD", - "metadata_key_hmac": "7FB95D5FC94C8961A95FB07BE8128524A847EA9353B1F1CB585B38BE60F30137" - }, - { - "key_seed": "B07121F9309C6A32A3937D28CB73FC80DDCA48F937CC9819E437A14FEAEE564C", - "ldt_key": "5BD101F34BA505417DB39696B39705BB2AFA5BEBE4BEADBB0FF26B4244940F2B34C28E8B7E95087751F00D2A72FE044906FE536A07A846EFFD67AA6771C6B81A", - "hmac_key": "8DFDF658D3BFC4E482FE25C11FD81F3F9B71C20FCAD59CC2053EB3FF23BCA90B", - "adv_salt": "D433", - "plaintext": "F46AD7D78292E7AF94603AAD5615B42F8FF117F9CA7AC56C55189BF30ECC", - "ciphertext": "0BA3E268A0BA62413AE63A2DF4DF4465A3DAB09E7D87FE5FEC79B515FC52", - "metadata_key_hmac": "91D65198349B8D5AAB4BC20D5C5EB55B8DB1DBBCC8016390078343108DF48CE7" - }, - { - "key_seed": "16EB091B388ABBF530F7C3DDE8BE8A4E2F36FD738B0C520B2B8873D5A39D7EFC", - "ldt_key": "9684092E2C949D1FA7BA03CF5EFA43926743761DEF9200EF0EDEB1DA82945F052D4EB19D262F10B88AB19FD853FBE2A80B14AADD8612CC46F6A95E4EC33CBB08", - "hmac_key": "7E6C9673B48E9EF9E18DB6F77FAD4A66C564A5981BFDA6481BEC0B941266A879", - "adv_salt": "836C", - "plaintext": "A51282B8D1A391F93CED3997D983F0B3397DD22D82F1998D82", - "ciphertext": "EE7988BFC2E2F00A293CF2BBBE1F3A059AE22C376C68CC070F", - "metadata_key_hmac": "98E45E977982DE8232DF201C239353A289A3CC74016924AB5DF2BB8AA766391D" - }, - { - "key_seed": "593F713B1CEEE1AAD58F05B739FB7D09DC36217D2338EE5A685295F7F084875B", - "ldt_key": "6E8604E1E78CC0FB19B84913691F26CC1C33199AA539B8FB99496D5038018B57CB67761DB438FD50D7ED186E215E322B536C8BD948F0769FAB910308CC54C5A1", - "hmac_key": "65DD06E50DC75C0DAA4C3201E0CD845099DA9405F61D4B471EB94812F932E553", - "adv_salt": "396A", - "plaintext": "DA236C79191CED8BFDAAF9EF4E4B0BFF4EB5F2ED6A930937D6B573E77EE1", - "ciphertext": "A52ABB15DA485DC6E1FC850413A875D79D3CB9C8BE1891A5837ADEA54B33", - "metadata_key_hmac": "C3B795131B2C970F92BA425666FE389CE11ABB52291F69D723E75BDE1D9F5064" - }, - { - "key_seed": "C19D74623B265D8D7F07CF5B9F099B76899ABBBA1DB819747909F2190EA25EB5", - "ldt_key": "797BD489E98DCE10E524AE9E1164A0F68FEAA98B0F4F97CD0C84FD3D2AB2E14CC276F3818CD565298244A13D3A490DF5974B72BBCCE294A2EBD0C1E24C5A010F", - "hmac_key": "A802F477F587F9D821BC493ECEE500B1D887119F1EBB1886284748D36F84D15A", - "adv_salt": "676D", - "plaintext": "D85AD63AEAD575E455BBDD8B2E5A42D18E87A8", - "ciphertext": "D3BC41EF27122C40B3D7CEB7445BCA3B3ABBBB", - "metadata_key_hmac": "5D220323813E77391183BDA887549D48BEEBED35111D6893ED003B7863389F68" - }, - { - "key_seed": "7BF3623220392AC5B804A005E6DC96A6EC32108FC22EA371325129A3B3C0934D", - "ldt_key": "484901A37BF4E872385A32AD47652A4289ED23BFBECDF7DFEC7ED6087F57FF5478E7B16323CCEAB9369FE99F43EFF332C1259C8C5375B2B274557007538AB73D", - "hmac_key": "3CE9A2B879697EED758D331DB9FA887478266041FE76C377C7BBB97C1A2841E3", - "adv_salt": "7170", - "plaintext": "570E91C5673CD53E569555B65DA830E78EBD6D7201DAFC94C899E1", - "ciphertext": "805DAEDCCE7DD993B5C894241FD07A7B6FE0227F8249AED9960D3D", - "metadata_key_hmac": "D741CDF71C6B87C90934C5C69E50776E9DA12A7046E73AFA8B9DA4E39B6DF366" - }, - { - "key_seed": "0B4244B762772BFF2D25B6AB24C11E1CBB862405DA2207F5261FD00D3FB2F41F", - "ldt_key": "652713E03311A04E642497AD242CFDBD85EB76CCAB1D0514F0424D08CBE5A24C4860B09142548AF9F27F54C060A8A3EC352ADEACF35D92582500104F27A29590", - "hmac_key": "A6E2A5880FB0A55EB630DEC32097D5489EF19F4CAEA7B63E8FE2F6020FB454BA", - "adv_salt": "9DA7", - "plaintext": "EA154B7C6378AC3F7F73B081DD747B98B23C17352EB1ACD548CE78F124463A", - "ciphertext": "79F1A617F91E96AF2BEFD5E94524EBE8CE632E385926E69AEF006C46C26155", - "metadata_key_hmac": "E5BA00E38C5A01E28EAC7E969824D76A6F34D8ED7F9EA8E20C9ACDD3FC4EC3D5" - }, - { - "key_seed": "F8E333AF5E871B1F0854914E14544C9F2697CE374383911C73C8FBAD8C3BE5EE", - "ldt_key": "A38E2E39FA60B949F1297FC3527926963441FE5A5004F0AB90BED92D229488C9EBC12C27B55ABBF8D81E10C2318677A81B1490749AC3FA23034395B8897BBF82", - "hmac_key": "F9BCBA55316A4DCCE7B2410E2886C5BC8E53DB210FC170BC53297A1823F78CAC", - "adv_salt": "D4B6", - "plaintext": "C749BA7F2512B6A7259269C1610770ACB14751298FF767957055", - "ciphertext": "FB01C67DA9E157F9291E28D33815DAC5C3AE12E7BA2FB0C5320E", - "metadata_key_hmac": "0C05F69D3E64ECA65B789FFB4AEA169E967C25C55B389D743A83737F66EEDCBC" - }, - { - "key_seed": "E5F9C362D4FD10E0DAC2A4BE4BA4EAFBBC5C4AFB3CA9820A70CC498B0734D4F8", - "ldt_key": "E3A1F5E8028DCDB21CF5E3D200BA4D728A36602E195B282B12FA5340EB4811EA336C6FBB531C28405B9994B9F55616C8C70AE3E9F5B0F2AE9C3FF5844BBC411A", - "hmac_key": "3D5980A8A1F905A098834D4C1E65DE9D3B341A95C10FF34B2AFA0C34555FC920", - "adv_salt": "34D0", - "plaintext": "394B4B158FCE09D1C525D965DE57A7A2707E", - "ciphertext": "66F01992CB72AEB6A4AF3AD8B29D752933FD", - "metadata_key_hmac": "02CDE2667F28741DA9CF4DD2A315AA088631012B142BC93B562A1E5F93DB6519" - }, - { - "key_seed": "BFB715370C8047D29D04F0FB33145DE2D623E3D47CD0C939225FDD20E5180BC4", - "ldt_key": "A93BB3594B683FB42863E88C23EEDBE0624DE923B1B946639EBF81288408CDD9CB25F9296C73885CB316E3EACDAC80666325AF8FC79386B8BD0BD392B02BC62D", - "hmac_key": "8CD11B7D362BC3134AFA622E973B831640BABB28AA7F2552A0C8DBD399348C43", - "adv_salt": "FAB1", - "plaintext": "BB4D8B51DE4FDF3AA54992151E6F528D", - "ciphertext": "67948062505D79C2BE4245F2A500935C", - "metadata_key_hmac": "6DA14EA7C97FAD70D6A274A279BBBF5784A40EC9226B2CEBFFE2F2F780C57607" - }, - { - "key_seed": "33BDB4C8FF7F5E4EA8FF024D8B50CA23BDC925F469D196C7A06F572E3B1D5B67", - "ldt_key": "291ADC21691BAD3974A8B7B9898D0D2A0B9EF76E96B5B46B762D447C3D42151DEDFF7A1E34F3E0E3309F0D377CD12AD2537ED00D951DF8D99F969FE04979D55E", - "hmac_key": "906C6E4C7DDDCB37D49B7989FDC034B00C858CEFC6E8CBD95A2E42F2315691FD", - "adv_salt": "EA16", - "plaintext": "072287B39625D9FB3C6251B5E4F87B4E473307BFC66C4AF57AA4DBBEFB0F32", - "ciphertext": "6AE99A8C1F11C308918297820F1E98ACDFA7369339553A95B2CD44C5C6E039", - "metadata_key_hmac": "41507F00272A4395C00B1F1F95A3BC62F2DB8B397D508D287BE1546472BC997E" - }, - { - "key_seed": "1DE7BE2135369F3554E58C0AEC11B28EB1082E47E5373BD6C33E27BEC88441F5", - "ldt_key": "8DCA3D017E1AF638901A7EC4F3ABAEAB5042AD712821052B7C9482C0D132C189BD8DB3CBD84F4683E948E5B0ED5A57354012C1C1B2BABD63CA2A1740382F3926", - "hmac_key": "83D9696758DBA51296E7F7CAF9A883C5DD29C2E228D2639B8DA4293AE5166ECE", - "adv_salt": "D9A0", - "plaintext": "56B94B01FB85F26DA07AC9871EC0435CB0BD2EF592AD8AB2", - "ciphertext": "D00C10110C4CF9E10294C41BAD9E4B2F656B92D437E6715D", - "metadata_key_hmac": "78DDE51A9D2B4FCF329ACACCE9996D4151B9450843A5B6FD234EC7FBAF76F15D" - }, - { - "key_seed": "8D30198B0BE682C467BDE246C0B5D17F269F5A5CAA1BE03CC91CE53DB89F2065", - "ldt_key": "9CE88CE3DE410005309A2F8050E65331D2DC2F43ED63025975B1B5E11CA00EFCA4E800B8454B578CFA426721666883FC49C1D828B34C9FC4D359F2ABB8B0816F", - "hmac_key": "8AC75FB664DE0D535B1649598A0933E07B15CC23E0CF20EC3DB58C67F2BA20ED", - "adv_salt": "2383", - "plaintext": "3AFA3B57F287BC133C50753860727341F8C76304", - "ciphertext": "5EB125210C7F4A434AA65F37061A1D17EAA3E3E5", - "metadata_key_hmac": "7B387B56051C2A1C0E7DEA987B3BD41179BE3594C94D3B2C16B54B8214E6B3E4" - }, - { - "key_seed": "938B3FD1182C66E7F3BD1C57C79FF3FC689ADC74582EFF313BB088C7D35E29F1", - "ldt_key": "553D293651004B38DC2DDBF30B4C3EB88BB2B52BDAF2A1D16E9A59197B41CC2F828D60448D693CDE6F269806F1F0D7E6926BD7E3E7256A0A54B440E1F7E6E765", - "hmac_key": "0A6D801912A13D138DE7888B57D5EA2A6B09264EEEFDBD2D0F90A4D838CDD98B", - "adv_salt": "289D", - "plaintext": "395E83ADEB08B0B351943B05214342EEFF8C58A9A460FC86", - "ciphertext": "B28472A8655F6ACA528FD326BF78032749159C02E67EEB7B", - "metadata_key_hmac": "B54FF0C1F02E244D283D30518DD29F39628C7261A33E4EC73E23D45BBA271637" - }, - { - "key_seed": "45A3FB6F4926BB2CD90E9A2219AF199CE6E22757951F3C534B97993049439BBA", - "ldt_key": "D5FE7EBE602FE69EE6C4CE161216B379C2E1541E1AEA42AC7180D0CEF246717E550A1CF18D2F9F36EF68450CECD38F77F8BD7E98851BE7F4CFE89CAC8343456F", - "hmac_key": "AB03BCE03F01CD10ABE61101BD662EB2052781BEC469A8797983D11A026621D9", - "adv_salt": "6268", - "plaintext": "FB8071BF75C87DE11ACB1A66B98CC640B67A6A6BE6059A0B5C264F", - "ciphertext": "F35F1F36EBCE7A4564D5E1025EFF20EC05EBB683DE5A4F0E066C43", - "metadata_key_hmac": "11C4918F0BBF662778B74461EA270416F54B0936168E5F068BD8BA605257D934" - }, - { - "key_seed": "BC3C628222F52DAA7DF389745DFCEF6C9FE1A4348B0260259044D83252229F89", - "ldt_key": "1EDB931C068100750CC1A2003C8EAA1B395DD61F0DAC1A19A6D2C5CA743366E082D392A50B5D338816FD9EA5D683ADD2EB8052BF360607D164ACFBC380A56F24", - "hmac_key": "8AF7E33DD9A1539042CCE8236479A8C209D24CDEC6FA46D8602497092339F3B0", - "adv_salt": "96E3", - "plaintext": "12E5FF905D0EB084A17EE6203F7A041EC8DC5D65E5EE442E84EB11FCDFAB", - "ciphertext": "297D54356D7DC53C6B52185E92E810B4BE02919BF84C7C60810007660216", - "metadata_key_hmac": "E4C26C3280B1198BA1BFB3AAD1E93D39B45B38DA0E14649EA32F2FD1B6E3575A" - }, - { - "key_seed": "FE59E191E1F37C4895B5CB9A6A2BAAF4D3759A4806D41B04710CA1B02F134BAF", - "ldt_key": "D510EB1353CC86205D7B400536641509974D44F6B90D2F9FF7F4969DA495EBD2C27AD260017AD1D5963ADD51FA7344BA1B6387DB8B33BEF7DB773853EF45222D", - "hmac_key": "E02610EA8A327590E20764D2F4EE4D84584459AA674235D01DCFF39AEACB1BB3", - "adv_salt": "30FF", - "plaintext": "04C28324AEF8E9F7ECDCBE90DA9F44B3C421F663C13D5708DC57", - "ciphertext": "6F3CC44F51BA5A13EBACBBCE7F01952EFBEA29B861F5FF9ED4C4", - "metadata_key_hmac": "561E4B55FDB4D3776F1F4FB2EB285CBCB059EADE18CEBF26A0E432DF712CB8E0" - }, - { - "key_seed": "F1BCE3E694D3E705D4A2A19F75CF82695E21ECD91A46B299DC84E2CF107882F2", - "ldt_key": "CEB2A23ED176C85C2FF7BE55FAB82496F7F164CBFE4C7F71718CACAA83B14820290F98F20BBD6B935C3DB03B85C5B86F464D309B171AE489A265E78A04D92E1D", - "hmac_key": "F1558C37EFDE507E43211379F127B673EA7F071A82F371B0B2D2A21D7DB02B6F", - "adv_salt": "8972", - "plaintext": "2C1751CCCF9D86EE6C90876C8242956A5CD7E1", - "ciphertext": "E09B67166DBA26E96852011D794F7E25A8827A", - "metadata_key_hmac": "FEFBE1CF5264D0065B12B300E33D61B6AFE1B1FA45BECDD0EBDA3B8599CF2F41" - }, - { - "key_seed": "EC22763A7622C4DB44CF765844E3F4760B331F56B9E1FA18F503252D2A83E4CF", - "ldt_key": "00EFD0A14327AB1565E25738ADD19A69ABFB7F198A5F9D4BC36321955FB1AFABD9D542AF0A1D434A714B984FB3DF5ACA6FF55C866D277398D76D7646AD6F60A0", - "hmac_key": "BDE86FC86156010C74FC6E28B73FE6381FC7D6BEE356ED3CF7A0CAF1D6D4AD8E", - "adv_salt": "3818", - "plaintext": "D8741C307DCB11972F993E89824E3CF4", - "ciphertext": "30AB89B502BEEB1E117AF6F150AE422D", - "metadata_key_hmac": "17A5E8E4F289549AA9C4C168FFC52B4334D4BA5642DA922D72192872BD29E54A" - }, - { - "key_seed": "6BFB5D9559236AA523B36B188FDB1AE6B5E38B73D40DCA7A5C3E0054E78C56A2", - "ldt_key": "A603FAEE39356225A060A05067944537F0259259E3ACAC6A1CA7D07AF1956128F1CB92D2F8A8DCD03F94665C685B8567A4BCA039BB3DEB3CF6550F9932A9FD90", - "hmac_key": "9CAEE450D7E3384524E699BA71BF89E80D5C249F4E096FA6340075E146AC50FD", - "adv_salt": "FFD9", - "plaintext": "75D5BB5845EA6038750E5BAD00FEFE436CB36B7779E4ED882EDF2B", - "ciphertext": "BB4E1D807A49C43B70D7F44DAD18B34F53686A8398B5BE42945B2E", - "metadata_key_hmac": "07B6D518CC5092EC628DCDFE72372741C431E01E333E6E51A1E6EDE6135030CD" - }, - { - "key_seed": "2F96CE3443E163E296F7E8788536B253445D253C0DE5D259B6FA79E6514037D3", - "ldt_key": "7BE961F2FBB8EC6CF4F4BC3B08E3235584E359DB19B38664675946F0D6395CEA72B0784F33FF429D440319CD3A3C019C84857DA0323B2AD556758A84714BAB91", - "hmac_key": "1F12DBEFEF1940B31C3C8DD86A1AA321FCC017D291AE4EE7329CE5D1C77B0118", - "adv_salt": "1A9A", - "plaintext": "C9B01829CBD1D71BD08704C914737721FD5A68", - "ciphertext": "325FD73EA2805026A763A2B38E2E73CD0A1A4A", - "metadata_key_hmac": "6823AB7F3B05C2DC43FEFD1B0841914CB66039FC4DD4378D699EEFC8BC2F987E" - }, - { - "key_seed": "4A88D683C9602276811F22E8A1B1A386C49D18438A8774EB68F9E1F47DD60A4F", - "ldt_key": "B85C7730669DBAE4E813FA0D1D317DCAD6B3F44BDFE79ADABE5C3B1EBFA21DC7E1E100F88EFEFF99DFFB221095ACFC73808F223416C1998A3602D7A7D22F8C1B", - "hmac_key": "92288B7DF8AA76139D235A58014F5328A37A508CA793AD52259CA5134F964078", - "adv_salt": "956C", - "plaintext": "2E22E38D3352091630AF0212FF2E8E3B3BDA4D73980DCE18519C935CF3F648", - "ciphertext": "DAE85D75F2E9EB829A0048A28A21F08AECF692E4A7D2C664681FFE7B625C77", - "metadata_key_hmac": "4FFA58C296880D6C3D3307D3EE0E1642CD6B398EDD36A44B68FAC60CA9F8A307" - }, - { - "key_seed": "107C2FBD9699F8A8D5CBFB34A595B168F01C6D84E4184D267B2A557190CBF3A1", - "ldt_key": "D07881A7CA0E220CC94CA8C13DF3942CBB7531C669730C4025BE564BE06D9400D01BF6EE08FB0E08F9398A8ED88045BED02A606D5CF51491A4E30724F4CCBAFE", - "hmac_key": "88FD72F6574A0CFEA7DB62714C03865768526A226F9A0349A9D94B692166CEF5", - "adv_salt": "C970", - "plaintext": "86DB18B1DEE5FCF1C62B6EB89418D31D0E8CABF8BB59DB42A78672BEAD", - "ciphertext": "B10F0285EB9FA1FEA581A130BEF5266F3574BFD8411D90762847C37595", - "metadata_key_hmac": "9BCA0211FB695146728CA6F0B1ABD243527EC9F577F4CB66838677C89FBC9F09" - }, - { - "key_seed": "B669795FC94A32E2CCEBE3E8CD7636A53F37C7AF7E8F03811E5C50E507B1CEF0", - "ldt_key": "E7BDC44FFAC5A842DB4BBE84955B3EA95F7652C7FE388C206021E592A4E63ECB09B56A790261AF1B3F727160A2A8CA96CCE9CE751B8CB97B570DEE4E8B904846", - "hmac_key": "86278DD1C9BECAE43AC378AF37689466A281686A75D0793705856E39132A38F5", - "adv_salt": "AC11", - "plaintext": "32FF82B1BCBF2C8D2DA1986FFA6C909A0EB4DF17", - "ciphertext": "507E2FF5FC4C017695228EF12ED482429B5F4483", - "metadata_key_hmac": "4F1F2CB7BD8638842DAC9277DD0F498874425EC26BBF113D7D499B078846096E" - }, - { - "key_seed": "60DBFE2A1B840B7B1F04DD9980885D8537ACC25B2FA210F5B494A81FE54EE81C", - "ldt_key": "C8C8DD7BBF2430EA3EF2F01C3259A4E6D89068D5468CBCD063485DEFD6A7011D330F461BBEC8750E02FD1C297D344C80F22F41898C9910CABDFE8B2DDD9A5A47", - "hmac_key": "9F980970B706235E2969A181D14FD7BD1EFB44BA981B597497B2686C9CD8A16D", - "adv_salt": "2385", - "plaintext": "6AD53BD901C67A9478E365A42943E2CA2DC6A41B9CBBC0B44715829965B7", - "ciphertext": "46BF32DA2A259572DBD41BEEC104ADB7DBFADEC7B0B8B0EBBFA2455A6AF0", - "metadata_key_hmac": "94976AF3312558D902FC77B7807386F1D163270522A285C14FB106C2A890EECA" - }, - { - "key_seed": "9653C6869668736549125E0F043308C09C33B1D8680932CF879A651D250D92EE", - "ldt_key": "EA277E82879A79A2D8A0F9750EB54C8743C75E3A1F9CADB6BE90E91DBD3621127295198F9A40EAC2F8949DA1F2BC1AF15C91F5BC64BFBAAA58FAC71A602DED2D", - "hmac_key": "4E25E4C1DBC0C4AB3C35AF2CB71F2F49B48A4E797E982A69DD008BCC63288A22", - "adv_salt": "42EB", - "plaintext": "7FC211D923E0FDEEF1A133CC4C8A54D755FEC60086122E18A2C4FC6C", - "ciphertext": "56830E1D523544F48C60A79F7DC2658D4711A69BA1021C49801F2F8B", - "metadata_key_hmac": "CB43679649B990619458219EF3BBC96FF58D01AC04453D84CA55111A1FBE51A9" - }, - { - "key_seed": "B660620A749423B87AB51CE3A9DBF52D3A49C4B4E9704CC491420F3C02673D84", - "ldt_key": "1C45A44A706B7CA5144FEDEB205E763EF6FA2A3D7C8C962EB4449458F3CE84D074CCFB6D64CADA87ED3D2B1BDDB915B04AE9A70E0732424A520AD2F2912EC148", - "hmac_key": "B19D5B3A46DA48B4A9C5BCF1017AA86BDA4D89AF45789DB90B3599DC72FE443C", - "adv_salt": "F778", - "plaintext": "AB7AE9B7E6A1D1C256E5E4F44E88FD638C8D4391", - "ciphertext": "36892DA56C467D9E87CD96BCCA33C17D1AC36715", - "metadata_key_hmac": "42036409DACE84B0FF0AB021E649191A92F0B383421F48F77A86D229FF722279" - }, - { - "key_seed": "58F6B511B4E669AEDF3701BCE8BC36F84BC6128280EDBA2889C9A20D482522D7", - "ldt_key": "83BA91BEEDB08613F78D4AAF4B285B0F8568BCD26F0AF5DB966F4D940EC674F9A77A22B3107EFB1609F8B558458C70D78193709AA204D5E62016F200B9B63E6F", - "hmac_key": "04041ED30C1FF71C51727DF8A6929257FC8A4E8D4BAE0E67B45153F598115579", - "adv_salt": "F166", - "plaintext": "11055806D37FDEE2634CAF81B6772788", - "ciphertext": "3154AB15C5FEF46C91504C32F561E925", - "metadata_key_hmac": "340A5DE98A25C36590E6C9FD70E7F33FE29C00DCCDC875F596E3870A3F7C1D6A" - }, - { - "key_seed": "6E37788FB48A39C046E2026A6433E1D223BC90F1D4BEEDFFCED9F266B6032906", - "ldt_key": "D522AAB7AC074824F08F5967F322522447F794188A439BDF931CE1EB13ED3A3AECC757A68E34B9010B5B86F4E10D60355298570F71C9E714A8150CF167156CBC", - "hmac_key": "5F74717B967AD6B134546677FA20C3DC05EBAFB9748A3B7E2369663B11DC2AB8", - "adv_salt": "9DC9", - "plaintext": "916091AC15EC4E55EBD5BC22C613A49B659EB19A5242211F500FB2F67E", - "ciphertext": "29796CE84C4E554E97ABB5A0085772D067AE41C2AE256C894CF9ECE691", - "metadata_key_hmac": "7B20F19C37450647BFD03C7F3B1EDEFA93E8CC0CFFEFF346BFACB12B67B58D76" - }, - { - "key_seed": "CD8A564B17E9FAD9A3BF046EB56359528BFAA8FE18A6C0E1A9451846D94E515E", - "ldt_key": "5F4D152E81F2E076137B43C6E66FA2F2ED4ADFFBC12488212DDC81436AFD3E77BD57D0AF7FB3D12FD989D31CF74D983F1C5EF02D998B2BFAB6699B94964DCD42", - "hmac_key": "FE433641EAE1BA1B4B834AB8D3F0C34ED903A48F566439A0F4D0AD0D5A54BDAB", - "adv_salt": "F138", - "plaintext": "2817177DEAC6DD1D7C30FB23CC2100FA734BE5D0423B5A53C63ACFFFD0382D", - "ciphertext": "5773C62B9EB57C23D724706D93F7EFD8D8ABE7FAB86591760CDB93D9303882", - "metadata_key_hmac": "68A929D5927F49AF93CED5072E52A66E99A5A2E51B371A7E1781AA6DF44D6B03" - }, - { - "key_seed": "AC1D4BBBB9C0922D3C6FA64E52BE3ABEC411DE0DA32AA066D2D5A60F6D803A0F", - "ldt_key": "78A2FE1A5CEC40E33E35A872FEC2902EA5B2E3C99C32FEF0500B6FBF082FCE661D2C52F2499CC3888FF63065AF79C3508DAFB7C0F911C746B95B5AAE403B6054", - "hmac_key": "82E9718FA9261F37D7D6729B4C05AE1A046182EF3B5B3D430387E6801C805E82", - "adv_salt": "296C", - "plaintext": "3A717F2F0568518635B3E2851BCA6D151752F1607F02588E8E1F77", - "ciphertext": "E05DB0E55C5FA750E7A2481A44E1080F9D49855523FEC5F5C01D35", - "metadata_key_hmac": "E395EB74DDECA7699C112CAA848EE2124558843F44C5E1C413121A47B563334B" - }, - { - "key_seed": "8D531389F16845D838FB65633C53BEABB14EDFD3F46B4D59866EE13E63879D2D", - "ldt_key": "F1B16139D909BD76F86B2AEFBFDF035C0EF7D5B5C2980DAFC4824A1479D908F8CECA968A14AF6C659E47C6A10C3AF22A3CCF092E7929BF764158105A25874F6F", - "hmac_key": "DEBBED4EF9C2FDC50AC25E977FC3250ED187CC8AD5F067DC01635B23A9E93FB4", - "adv_salt": "FFDF", - "plaintext": "38430F14331A2D48355A1C9F56A1AB0BA7A27EA132A7071E09", - "ciphertext": "C3F9DB294E6A735FBE527B0C79FBA8ABECB00B31CC7A67B2A7", - "metadata_key_hmac": "95DD1FB3D3A595FD72C041B3F79074C3214BAAC2C18E483CFC4206D64AC4B64D" - }, - { - "key_seed": "08C051A56A4026807F185AB8B1F9D6D988B275FEEA0E407136108C707158964A", - "ldt_key": "84FE0436136F9934A17ED5660A270E6F54B4E24F0969ACC5B84C6078DA720BC103C84EDA3B93C466EDCCFEF85B5D4C462F12423125B05324856CD6C784E086B9", - "hmac_key": "72BF447F5C5DA8D513080157E7676EE756ECACF346ACDF9A1D561DA359CFDEE8", - "adv_salt": "84F7", - "plaintext": "AA39C2A62A38B2B0340CFBB3A5C4E988750DDD", - "ciphertext": "49C146946B7A2D0A8A71B5E171BCB36429256E", - "metadata_key_hmac": "FE8DA88D4358BD47959B23268B7770C1322E1FF1E6E8E1DFEE90ACE685260E57" - }, - { - "key_seed": "83F48A68E7947230E032BBC32641F52278B85CA39CDBDECCCCB0F4BFE7F0E77C", - "ldt_key": "2A2012F1AFB7EA08CFA3B81E6DEABB492850F7E411F4B7FF0588CBC94B2E0D47C10A267B846996AECC466E81AB9A26509D1BB8139688CAC1FB7DFE269B92A2E5", - "hmac_key": "AAC0D02AB54DA3F59EE5165D6267BFFBFA441B4C038F2FACBC8C47D09E7B89C6", - "adv_salt": "59E9", - "plaintext": "1E1099C949E8833EC2EEF7FB9114C51F48FE", - "ciphertext": "F8E229DEC34641ED97C53AC106B9D4C10C16", - "metadata_key_hmac": "6A14F39AF418A9E90CB72E5134B9E192204D6BD4A014A73EE4B3561D69F9996C" - }, - { - "key_seed": "25ABF61989684166CBBF871E353B74F53292B922D3812BC0FDB23D13CDC3C280", - "ldt_key": "311EC9F125A3987903450884C49DE77E27EA7A476F95128CBEB2D2EEA928D081BC8C7EF80B3CBF62C3227F6E56450DDD2DEB355CADD8884B96A0F72C874B0500", - "hmac_key": "23989F83F9D09F23D2FB15EE7C52362D23616C1266CB3397612CE7C11B6F5E54", - "adv_salt": "6094", - "plaintext": "3A9CA922DD4CCC25367907942D630BF0C3E7", - "ciphertext": "3BCB1D893925FC1087E97ED294D3346791E2", - "metadata_key_hmac": "348BBAD5CDF30488980D723F5FF74221168432D8A7D6A068D4AAF6CE30B92EF4" - }, - { - "key_seed": "7E870AEE530314D6A7567BDC977EFD10A88FE5C8FBB4BB36B930B3AC44165DAA", - "ldt_key": "C2494B6FD9DF81656BB26A24012A63606365F9A8520AEE8B83855556AA16FC6B7AD913EB71F5CD6EB2D50BC7FCA736AC397FC5086985AACEA81C81AF87BBA281", - "hmac_key": "E2099534726B7394D79012E3184611784E190FF77A1D1BE5725EDCFC869ACF6A", - "adv_salt": "AF79", - "plaintext": "66932F49484D0F989AD55599DC2169EE311FE20E38B9A16C6346", - "ciphertext": "01358398248454C6B1AEA844D6CAC1758D2ECE788AF8455055F8", - "metadata_key_hmac": "61B14A3C1DE1BD60BA060735FA8A36EDEAFD8602B1A0832CC29EC3D2945B9BD8" - }, - { - "key_seed": "C7BDCE87471D280868EFAD6BE11D01784A17DF2E21B2C42F40E645ED53515A04", - "ldt_key": "BE67CF76B8DA9C1CA61F483E516640060C7E6AA6123BB96EACA540EBFCE809DBE7121C7B2D7A8F836C9FF8E937EFDBDFF949BA8D1D379F8D503C428AD80B62EB", - "hmac_key": "20868F5516F580BC39A7DF3411D4BD749CDDBB4C8BB5E1012E94021BFE89464A", - "adv_salt": "7DFE", - "plaintext": "69CEAAC45F821278B72E282177275B8E9944FD6754D437E0F3D4", - "ciphertext": "00A52D33E34C2DDBC1CF8D60957EA3E4A8A2F1B9EC96DD74A5C2", - "metadata_key_hmac": "8D1F86151A921843DB626DAD5A8A6025DF69817DAD2464BE3B6BE20A978B9339" - }, - { - "key_seed": "E486CC16E8200FA38014D822284E1DFD6FC672DD76AA30A15402A12868C456DA", - "ldt_key": "5FA855391F68B0B58C3E5BEC9887E39A3D7C0EC29CCAFB7647A5A91CEA73803F3419CCA956A4D03343FD65F36EF520FB888590ED2B6B2EC1A16B30870431C5E8", - "hmac_key": "DAF4E7480BA7C1DDBC5322BC6B7814B2191114E963DDEA50B16A831451CEDC6E", - "adv_salt": "0E60", - "plaintext": "1C3FE453F872B66095CD3CB88BB6FAA77D59AF", - "ciphertext": "ED89FB6E6FAA21974A4A403E7E40EF92ED5F74", - "metadata_key_hmac": "31463EE4DB1DA018FC809A8B6BB6A36F151219C237F8ED8C10E0460DB666355A" - }, - { - "key_seed": "9AF41893CDF256D94F514EAA0BA39FB189D8AD01205AE4110A398C0066C9A7E3", - "ldt_key": "9FC81F3E1159A25C0ADF56BDD16307F2AEC45BF5FB4B10A8B4E31BE30FAA6915C33BAA7CB538427B63CF4831EF87969931B153381E734E66160218C55C53E2F3", - "hmac_key": "55E88B5DE0531B144F06E1CC8625DE501997BB6B4B77E31A5136EEBD18ECEC3A", - "adv_salt": "CC47", - "plaintext": "7C0A44ECB3BDC4E0BDD02FB438F4BAF2C449ADE8A93930", - "ciphertext": "DFA844BEBAA59BEE88E6518DADDF665B28953EA74DFF50", - "metadata_key_hmac": "453356617CBA9A6A7C211B496BD7C12D0439E906160AD93988242B85A20C5C6C" - }, - { - "key_seed": "982013E258D8D4CA7E3F932B3B4EC4D9D0BB4F59E773BA088C5DB261993DFB64", - "ldt_key": "B812087CC7F516F63D744E5316BA2214BF3314D394997A95B334F364AB3268792807C57EB1BC6944EAA19A3D168BDB15A2E9DB6FFB026DE8A58AB61211A806F8", - "hmac_key": "3D0188404BDAB7F999076EA9321A4EFC39A55002DEE7C622AEA1E8E1F7BD0115", - "adv_salt": "19F2", - "plaintext": "4D21D4A45BD54B82F33ADA83DDFDCFE38AD3", - "ciphertext": "5AB2669B6B5F3CDE17B853DD9CBF9D8E486D", - "metadata_key_hmac": "171BCF753AEBA62AA690554ACCCAC49DE5C7C4CC4BF95F1A6639D5E7054BAC6C" - }, - { - "key_seed": "4831215C060EC4416486BD0D06BBF8AE1C87CBED2C686FAF78FC143BD4854A8D", - "ldt_key": "FB4A94B958A53E8E81232A2288C9B50ABDBDDB405BB9FB27FF61BB0127280557F4462FC907ED63021DA56E5048D3209E495A8BA674423522E1DDF8EFD2992074", - "hmac_key": "C17765625DC10B9915731342DD4574429C87DD3C6EFD5022C9C4C34595966C96", - "adv_salt": "37C1", - "plaintext": "30A6E08285A9DFF8D5732E12986438F3A543D88751", - "ciphertext": "5BEAED03F32825CA05C6AEEDCFE8650E80F98ECCE5", - "metadata_key_hmac": "F363C143814A9C3ED6236DA6F712E936C32A9E2C6D773F2D033311B7EF9E39F9" - }, - { - "key_seed": "BF7F333ED03DACAB5398B5E68607FBA1B84060860A11AC859686499D199108F1", - "ldt_key": "76A979188272D1A0DFFA3E5F4C6D6BA6ED03259AC3AD0548CA673FC6758627E5276461C18FCB19871A7E8754FD248CC68107F73D788A08783B8C1A335B742121", - "hmac_key": "57B20A2325977E08DA51B649FA12B5E15043951DC941BBCAFDB114F544F54092", - "adv_salt": "0BB3", - "plaintext": "F903ACD0008F8DF45ABF1A73BC406622ACA5AD99EFE76AABD2CD608E08EC", - "ciphertext": "8C9F277FC17D2D44FF96D9D961685DEFC16ABFBA5D13FB75C8ABA0FD3155", - "metadata_key_hmac": "24D2D21C385EBB9097D0812C0A184E7B01A27490DBC30F95E1BFCE7D7C00FA6F" - }, - { - "key_seed": "AF8CFDE1ED1EB5A6819878AD5899D5AFBD9F0DEDD87931A919CE4C562216014B", - "ldt_key": "958930672D654C4591C793752A25E8EE363249AF86488B8031725527E9CFD878C6931B44A219B1B7DD7DCF53C8529E024D89F4BCD5086C009DFB79E130F4BB18", - "hmac_key": "77C306B7F177F9158CAD803A671871CA22C2C1CEA9A37B71FE79794E1D1176D9", - "adv_salt": "AC72", - "plaintext": "8537018520FACCFCBEF1AB47A942E1B0C8A3D0", - "ciphertext": "0325C312805B932A9316EB5701099E54FE47D4", - "metadata_key_hmac": "60148175D0618530DECABD4799ACC71F171B6D354691E97D1F75BD6DB8F6D475" - }, - { - "key_seed": "3F92B8CD12296A93D972407F6874A9B0B275FCA1D7128774716B9B44AF0D93C9", - "ldt_key": "C082B62526B0354A6EE8C73D673EC64172C43072B43D47CD43E78874ABB5FE678771D852E847B07029AEF65C61C10CE82A927C70EE9FA5D00BA91711CF36091F", - "hmac_key": "53310D7BC015532A1EBAC43E1B0F0897D85547A8A6086807FE027F5928607FC8", - "adv_salt": "649E", - "plaintext": "2CB8AEDA871C03D1BA51DC69745046C12C650EE6A4B22D12CE78FB", - "ciphertext": "59FC27853BB2E2E4CBA1FC875189DC73CA1D33B3A2DE23A8EEBBE7", - "metadata_key_hmac": "110111ECAFEA433A6FE6B9C48B51F84301B286E7723E8F42ACE24067C3669FB0" - }, - { - "key_seed": "A6950325CCEA52FF5CE7452355FBD77AC51821A2C0CC6659258590C8D92ADA53", - "ldt_key": "64D45B4CEA1B625AD2966C1670E4BDF0C7205F2A959A6DBE009AD340DE5627D41700E342BD0C1DA21F46656F570ED1230DF80E84A365391167160E2860B53CEF", - "hmac_key": "A6146EE57806226CF7B8B108C52229AFD8CFDE8ED4432E32C9BCD2513BB90A55", - "adv_salt": "B6DD", - "plaintext": "FA35612EDB49394BA17595F222FBC2754E0A419A7AC0C7688CBD9E9B3C767F", - "ciphertext": "C9B7F258E25073D5F5405D170036933D949838E7308C3BCBCFE6DB6E8F67DD", - "metadata_key_hmac": "A0D791952CDE3A40D7FF5621A00DBC148776B7837E97C588699B5B319504A516" - }, - { - "key_seed": "617DE18D574E856674621B463EAC834EA2CA1DDD33B62EDE6673EAC03F48DB01", - "ldt_key": "7A824C14B59C7B7684BE92648CE9DBBE893226A3260E00A3445D9EE1F8ED795C53C013DEACCB49D55A02CE84A317F5F22DDB5DA33BF2D716C0B7D9F6853F82BC", - "hmac_key": "285B5A229E5F0699D14801BEA4BC6165778054C8E693A7436F235ADA01041BCC", - "adv_salt": "CAE1", - "plaintext": "4029B5BDE7AFB3C50B047A5F601BC25DAD35C329A36D", - "ciphertext": "3DE0E528CBF25CA1AB98C6BA250EBF8CE00D06F0FC61", - "metadata_key_hmac": "BE3E3849E1C920A170CF6168559FB9B197B38109858F3EFCB68279C21C9D2685" - }, - { - "key_seed": "8E2B98943C6C16A32693C58A1161AB7BBAFAF00CFEA1097B5806A317ED13A813", - "ldt_key": "8FC56B5C11558E6B652F8DBF0041C2CF4593B81E155DA4CCBE49609AC0E09486AF6610FE6E5ACBF0936D8D0EC534E96AB10CF4775F92B5053BF2FB9D7F5EE7C2", - "hmac_key": "044BBD941C6E6C0EEFF8A0C555E93473D19F6B4898AF5A9BF70FABF23F93475F", - "adv_salt": "8CE7", - "plaintext": "B92509CC62B827A735FA5775218564BB", - "ciphertext": "67854E6A4DEDBC3ADD4EA4A0E853D0B1", - "metadata_key_hmac": "E560F853FC05FF7EE8EBC9269CE0B49C0491FD73E29322D575227615064044DB" - }, - { - "key_seed": "36AEB76E3B45B994361A35371FAD52DC728A90FEA7963A9408FC6ACF70F54193", - "ldt_key": "D30E4FB3D1E5401DF4F4EBFADA78A25DEEAE3C19DC2B3ED09415A2FFB48A0B6DB39F23462FF87E29C6D9AEF763B3E32B99C620AA8E8D756EC80B404E557082FC", - "hmac_key": "F3305A1FEBD6801AB41206A92142CF84F2B327276095A94006375B2B1DA6E224", - "adv_salt": "9B1A", - "plaintext": "C26F86704676F7B25CB64001686B251CB9", - "ciphertext": "907CA3B495D61F3826956618D65A622B0F", - "metadata_key_hmac": "19A23CA6F848521C7DE11588E1765466B0F2851262770322D5B9B83AC582A242" - }, - { - "key_seed": "389075E418B6A1C619DB81C3A25F768F8C33BB8E5DFF09955A87B6A32B715B35", - "ldt_key": "44E79BCDEB998525CC68C15C0D379C913C99E6880B15B80EED54B820ACBCF6041B3B7DF4270FD0441CEC05ACDABDE9A073EE324F4E9E1CA26D65F46CC379535B", - "hmac_key": "9CCB4BA78D70D25D9053213A0E1748C994CA38CE5A42F7A903BE6350B4828B0E", - "adv_salt": "B201", - "plaintext": "51B6999CE384C3C3A6E8407FA2FA3781B54A3F3EF6C61F47C7925CAF", - "ciphertext": "703417211EA1B58674D06DD811327227337A59C751AD4AAFF37A3380", - "metadata_key_hmac": "A1445E361BDC3C7A737B3BEAC511C6D0FD9782B6BC0EF2254CA77C1489F0F3D5" - }, - { - "key_seed": "F671C931D88D78D9CC31118092D123E86926D025E8B3695926B7D0876B6DDDA7", - "ldt_key": "18669548D3BC8236C019C944B6EFB8B60BA8AF3DD1F8F7FED3151AAFE4D56070EE99AF0685CAFA72EA60761C65E753885D77A889B0290F554875B37F47652D34", - "hmac_key": "D05B047B4F212CCC5A392378611522722A7B062E65B188F6B3B44E6CE391B477", - "adv_salt": "B347", - "plaintext": "D5B5C84033C34A70EB023395C045D649BDFD79775B7E350F021594", - "ciphertext": "F0DAA688C904859AB1DBAF8B3AA833BC13F9A6056BE9B937414DB6", - "metadata_key_hmac": "932CF0BC690A307BB5F02FCC388EA94DE58441BB8B132D16815B522BFBFEFC0F" - }, - { - "key_seed": "DB1C9AC98E541C8CC9C72E6C7F66238D343A91A6A3A33EF2F7546AB4B8B7107A", - "ldt_key": "DD98D681661D81489C2BD6129E6D7F667305F808D3275B66342D6A47FDE7473A60ABE1666C177383C4C45CCF0A6823E79F269F8B491E8DFE2D0306046C3A0848", - "hmac_key": "1FE0C9FB0DCEE2D1B95644C4B2E4F88C9F72611AD9794A5F18F05BD726E103FC", - "adv_salt": "E878", - "plaintext": "3FFC81E390AEACBB5966561B6726C6949D1E11367F870513DB", - "ciphertext": "F9FC49595EFF1AB575F7682526CD036824C06AE6402880695B", - "metadata_key_hmac": "7E52B09D92F882B675288104C25E17DD8070CFD78CAC299BAB4A903367FBD4CF" - }, - { - "key_seed": "6E76B182593F7B2DD6FA658E31CF5DAB5F5DDDE891A4585B6372FE6B3FEB57FC", - "ldt_key": "01DEBFAE8E615BE20A0C581A3C68A03205FF0E79D148E1402D5D5FD1948A7D26FC5AEC1DD9F0BE409204BDB9915EDC01F738882F4662322A4905112C1B2520A8", - "hmac_key": "EEB2093740E790CF3A0231BC06701F97BD9FB3F1F4EFA5E4F4E7771C8A97C7DC", - "adv_salt": "56E4", - "plaintext": "FDDA577E1B84979DB007BC7A3FA1A6D2E68539149C88204FB063", - "ciphertext": "905DA74F695F60AC01DB7B83AAFA2108CACDBEBB534ECFFAEB8A", - "metadata_key_hmac": "1EC6EC98754BADAFFD56BA5684A1C6066589BCEF6E3E8B073DBA049E6974F293" - }, - { - "key_seed": "06633F915364EE7DA5032267B80CDD9673C1307E0629BFB5172EC4BC1890128D", - "ldt_key": "1E807E019B269BDE087F7394D73647C1082FFEAFDA1ACEE060E24FB80862F3117E2A64E93549A98668776A2F0A693065AC03818F26833D7D8DB5AFB14CCD5D6D", - "hmac_key": "8A4F56C0A75EFF12CF5035BB934D29D26F69DF10368A7ECBF6E930EE42254397", - "adv_salt": "9BEE", - "plaintext": "C24669C503C8F725AF5002AE03FE3FABA3CA1328B902FDB174", - "ciphertext": "FFC10045E9999158B05869CB81391D213C0BD179771D42DB9C", - "metadata_key_hmac": "85BDFA0A3290DF03B08DA1DC895399D4261EFC63CEB3B9535D001C1E8D9745D5" - }, - { - "key_seed": "FDABB479A313776E95440648BC65B72394CD844601074628D4AF98A9FE796A10", - "ldt_key": "EF6D7D9DBF5853F602AB40088C44EC77BD960B19B89977610D09EFC6966BBC8AD1D3D01C529D9AFD9C6A098F876544C4EA3075ACA78FE48E7F440BB62AEAFA5E", - "hmac_key": "D64C0D5308A0464CAC76D3D4E3DCC2189653ED32C0406283368822A76D7DD8A1", - "adv_salt": "60E5", - "plaintext": "082669393BA15D7929EACB4AEC506627DFBD37", - "ciphertext": "C5E74FD9A5616AA14D03AE2C6CBB236AE58644", - "metadata_key_hmac": "93547F72D6E299FA2FA0DD443D94418F3DED56ECE4D9413C5426794621778057" - }, - { - "key_seed": "A3707E6C0C7947ED67E1FD8E47CE9B43A0ABE539E5ACA5DD056A9D940C612E2F", - "ldt_key": "884D6D9CE55DC275244B39489B386352C4ACB6C73202F274E8B1E68D1614CFBD61916E72C93B5369EE0669E5DC15110C4DF8C3BC6E74F715C0549D26112F5974", - "hmac_key": "E3144304EA455E4CAFB2B0B92FEE7FBC5A7063B80D7881B08C405573487733D6", - "adv_salt": "3594", - "plaintext": "3DC2614ABEC46AD9245BDFEDF3E90AB5DCDD54BDA57D591AE41B075C81", - "ciphertext": "0966FDF24C0774A04FDF4295AC2FD6085CDBB83A2FF13265071A57A914", - "metadata_key_hmac": "270AC4FCEB6A68B2AF9E453355E472F3A826F86880E7376B9428B8A6568E5CA6" - }, - { - "key_seed": "9FDDB21FF1B2D5EE2B1C70280757C1AC4B0AFAE49C7451D1BCDFA2830F272910", - "ldt_key": "0F8101DC92E00FA2903774FE987214ECEA4D16B036F23CD2A5344979983D6F2BB84898CC466A2A65D05F336CC8F7252EC48965E4D67CEBBCFBB04B21B48ED143", - "hmac_key": "066010A645379580554905B125B611A2EF57780C27C6F3628A2DC88AD132D9F5", - "adv_salt": "7BA0", - "plaintext": "82A976792715216048435D7A5E28263FD2B458C407449014", - "ciphertext": "071D6F551533BD63BA43D8BDAD6E530F7F377FAADA3EAE4A", - "metadata_key_hmac": "DBFFCEB7CD3896814DC58E17A466434A2BC791046C0C4E01B1E5EDA3D000F8D2" - }, - { - "key_seed": "AB4D2463F367B5BA727CBBC13FA9C72AB706F201BC64DE192DE1BFDBC219B7BE", - "ldt_key": "E16D3C6A029ABB4B7D5163A6A25B0ACB78E7971B5F08C3051D3006474D509743F88ED8833551E255DF3968F7F24E7C51124E2E87CA67F73AA4872C3880ABC470", - "hmac_key": "D826BB876AFE81B61F6BA5C3393F6A4DCF973D2D926280A1573008218983E8D0", - "adv_salt": "95A6", - "plaintext": "607FB840E8B048F4D4625FA0E5D743F3602EE464D43BBE14BEBFADACE2B7", - "ciphertext": "5B784C3857B316026480CD50FE8C5B3655CDF92217A2DCFB66786BFADA50", - "metadata_key_hmac": "E85C2D425E9227FA22516AC78E9517D29C48EF1CA281C1C07BFBE0BAA415CC2F" - }, - { - "key_seed": "8D20F9697E22B91CF93AA7C352B089D9A3297354589CE1A53B9B40F879C72C48", - "ldt_key": "D2854282B9675BAD6E79BB1D65FF19A6B2E0B7308FBBFB0C5781F4735D6C707C5514EFE445EA6854690BED816FE34C1B47B38372CD36849CADD1764A0BD24ABD", - "hmac_key": "CFD97E20543B0E9AD692E7381B1B42C774C70B91BDF39072706CB97ABEB6C5D6", - "adv_salt": "CD47", - "plaintext": "1F2F14E5043E6A530CB820C2758B9D448B74227A97BD2E0BEA934564", - "ciphertext": "580D1F5A222A20031D2D3F44B763EB815DBAEFBDB8C457B323F6D933", - "metadata_key_hmac": "A44A6C8830FD0FF0485B590EF0475B1F5448C5DBF7E13F7C20F68B13C8F64697" - }, - { - "key_seed": "F6B71D5239CD5AAA18564AA774D7B2628877D82BC68D6E0A13E624EB9451F2E1", - "ldt_key": "60E1C3F87F89B8EDBC2B45FC64378D01F4449302B84F7BF7FCA2A3012BB72FB3792CF55EB840B8843A84908586411B3324AD7BAF42E6C2EC40BE1F4F412B98F2", - "hmac_key": "C081F2666BC84CD686727A7431AD0CEE91179AFB22FB828624C52D1E0789E521", - "adv_salt": "48EC", - "plaintext": "1813610387059591A293B9D98FB30D9D0D", - "ciphertext": "FB831DF209BEC56D426A05EE003A2FF34F", - "metadata_key_hmac": "9FB36CF49F3B795E939B77A007BAF7FA991B98C8DE1B7926F809E2642C92B2A0" - }, - { - "key_seed": "10309B258D701F43599041C06DB1F3CE87D4A9B4CEC36414EE0D7CE255F58442", - "ldt_key": "63B92505655987A94A7E3BB6A36FC9141D94BEF3072A77D414CF0B05A080C1981C4FD35BACDE42DBBD6EEF20ADD063721404C921CBD13AB29AF6C614DF559130", - "hmac_key": "8C62F3E01B2D15A9BA355AAC65A1A687FAF4ED164C824AEEE528FEDAD2D15814", - "adv_salt": "4A5E", - "plaintext": "A70A217C659E6F0B650842272DFD5406380D2092058B758A0DB610E89256E2", - "ciphertext": "D0215D41075D0B1B0E4633FA7329268E0D8F0C4712EE8C3123D102D680B3AF", - "metadata_key_hmac": "D71636B40DCD5A88674C1289064092F56EBA10FF80262C0D4060D75F5D03C9AC" - }, - { - "key_seed": "319AA8669DE0409951869BDD8E187364B5E573FF4E9D74615651A3888E5B56B6", - "ldt_key": "69E63159756AE45791F9759493EC1671E7CF5945829E5D41EDC375220960F6B46E14D1BCCB5FCCEA476441811492F0E70492574047B8554D0FD5EDB134E42410", - "hmac_key": "5564DF9C3C2B6096B6A38F2AF78A1A663D9941D67732D36D172ADEF63B69654F", - "adv_salt": "28E3", - "plaintext": "39F0F9DCADB181522561E84FC46D34E3FCFE00BC12BFAF", - "ciphertext": "7B0F9B1191859FCA946F4721427C7BCADBFB5C0A2D23E4", - "metadata_key_hmac": "4F8802A57F2E9F82F7FE647CC1E30890E8881C7EBB2C8986BD87944013E78CC5" - }, - { - "key_seed": "17F3FA6C10FF6A77579CCD13E27AAC691AF8FB37D6CA844EC670BBD3DB03D155", - "ldt_key": "CDCA67E54E546D5C8B8AF84782568C9DF533597BCB808102CD1F2D62C6689AFEC7D3893D52BAA826C7B263936635F89495BA755F899A434554B10604398A954A", - "hmac_key": "97030022D81816F751E0FCB0EE9DD05839647DB0750C938EEAF5AED0AA3FB00A", - "adv_salt": "242F", - "plaintext": "8074DA96478FC4E9ECD3F59BFE13B0EC573D", - "ciphertext": "329F0E00D0F2212614C251CA8A8C50EECDC1", - "metadata_key_hmac": "C8F96DEE6E11AEFC53199F00FCA91E314CC1EA713DE70F05A775671C12C36A9C" - }, - { - "key_seed": "964C27CAA6BF2F825E41EA1F620E71F758E1D36FDF38512F5DB0BDC52AC3736B", - "ldt_key": "D3D8A93A8922B4274ED6A725F5669AEC307F523B0F6DBC778002559512E9CEE4883F8F30A87083D8F060F1745D6E4810E576C45ACC4D01DF0CC4DDED984C8713", - "hmac_key": "DABCD3EB3BA36EB49A3DF8FD227CC3E85180DF2896B19F12ACC33D073E293516", - "adv_salt": "B068", - "plaintext": "AEA44E41A42514CC1D6FAC97E781A9C407E1565F484FD077FE47", - "ciphertext": "75A0B45E8DC44D1861000EE619F8C14E3F412CEDD553231F5177", - "metadata_key_hmac": "295ADA83D819E4525AAF23E04BD2A6DA0B13E1B77661F95CD005CB9561C004B9" - }, - { - "key_seed": "4131694084A0F5262C980FE2906317562C10192185D04D1B75C26C22E686BF7C", - "ldt_key": "C4C6D1438EC865142134800A830C8A9282BA65D23E02BB3DE2AAEC36CB0D4B7615C1E0A959D70646FE9870F2900FCC56CF2AAD47E49318CF11097A4DA7193AAF", - "hmac_key": "F9AB08C53D16EB0F1276D256864F7062F688AD79C476BF320911444567B7C0CD", - "adv_salt": "884D", - "plaintext": "E842B40BB94678DEB414D41B60FF6056EC62598A", - "ciphertext": "B90D4049D479B7413A7F197C72B26F31606A6744", - "metadata_key_hmac": "AC26DB08DACCB7C09831E60A0D35D32992A3F87C736FD68D287776476E83EB6A" - }, - { - "key_seed": "67221C5A236C00EA542ACBC5F8B5E1A80B26D0DD3D0322F811165E58C312156C", - "ldt_key": "38F913FA317282391AFA810437BE8416AC2E3046F7A156D36E857D4C016F68F0D89A1F0162A3A36238EF920648033322ECCFF6F5535FBD7E9A673E3CA17F2D38", - "hmac_key": "45813BD36DD6911DDE03AD1C7897302F9D289731D15CC7A96A15C23ECB1CDA53", - "adv_salt": "B19E", - "plaintext": "1C5AA1067AA3B115EEA5D3E3E84BA2B11FEC946EA2A3000DA92CF9", - "ciphertext": "089C8CB3869212FD06AC69C53EC3AA1BE6F05418FBABEE91A25095", - "metadata_key_hmac": "3CA1371FF09C3ED2863D8CDD8DB242D8BF7DA729A9AA397AA41E13BF5F1C9110" - }, - { - "key_seed": "12F66691E13976E6EFFA1052C7CCD589063B3E3958489DEBF28C0B978F7AEADB", - "ldt_key": "BE49ED6D0CE4F218AA43FDBEDE9DF1DF61F4029ED04B47715B35EF39AF58A0C2D53952DB7D5D382F2ED481B3D1AF2650C17E03E0D360394D4730BFFD18CB9CBE", - "hmac_key": "D70E3A2C91CA7BCFE12F6E399849D798E06822088351038C8AFCA2B9C88C4184", - "adv_salt": "D093", - "plaintext": "DACFD4AB31F83481E90BE4A24D5D1DA8AE9AFF", - "ciphertext": "36411E0DCF60BE64F20AE1B3CE78D04FA1BC33", - "metadata_key_hmac": "89D101967A03B09679F10FA8180F0B0C93FB4C304DC5B43052EF416BA712C245" - }, - { - "key_seed": "14360985FA56AEEA01295504B697CCE71CA97F320AECF67CCCA057B3E6B8E1CF", - "ldt_key": "6A9161F3DAF50D1852B6D076B015C07469A92ED8A098AF98360D7D651CB3763262ABCE1F23308102CBF72F358D15C2E36388004BEB177D93DC804F835DD165E6", - "hmac_key": "B1DA99E46F5C4802DC600729025BE877DB66BDB0C2CED86C42B96FA89949EB5F", - "adv_salt": "E3FE", - "plaintext": "522C385C5BE019169734BC78060CB9BBAF", - "ciphertext": "69C9DCC4CD2AC58FE60463C786268385FF", - "metadata_key_hmac": "49F80DDAA5E01DB556F9C675558B5733DB710B94FC545537F9400904406C87A9" - }, - { - "key_seed": "5CAAFC9531517CA3FADF7937D4E3BAC96A3B927EC1DD30E44E55F7F781FF6675", - "ldt_key": "081F4D3B01082263E3C72AA40A02979FE308D2D46BB182FAA58790654E7D72AEE16054400EA773530D92A2195A037DBCF47D48E59B636C530BCFF99BA72F2157", - "hmac_key": "056363C59E47FB4D4D9CF0D7BE8796696A2B91070DFEA7D7FE197B63F0F623AD", - "adv_salt": "456C", - "plaintext": "ADFEDE24989BE8C725A2DE6A6EFC62EFBCE7C155", - "ciphertext": "F7E6DC4F7449E2C77D62AE1EACA091C8B2A0B41E", - "metadata_key_hmac": "C3516A1F01D8126FFD22918F85B97E7BAE27E511BE13AE1BB248F93497E09649" - }, - { - "key_seed": "0861E13FDE5F610055D2FE92F147C7792EED119EC6787B375F91246E583F46FF", - "ldt_key": "6C5711C97FC4B4E2565C9186DD0D01E91F9661BD92C408EB7048C658CAE9E32FDE306E62123C4708D340FD7C6FBCDB35613854457BAF42F9B72317325D0E99AE", - "hmac_key": "F35750F1B6C786CCFBDC8314B46E4393DB5D8D52A799340FE8D4C74A74CAEB3E", - "adv_salt": "61F4", - "plaintext": "25A29E046F7178A54B52CE7AE9FC5C5D6D4D", - "ciphertext": "722940807F6E2311D4BE22263489A4197672", - "metadata_key_hmac": "E9282C0B3FEB515298D39CE65680CE0CB1874D01378122C658705682A6B9E2E4" - }, - { - "key_seed": "824F5BB7A6DEEC43DC784F1C0D2BF162FB9ECF77A8FA0B942030AED0AB41CC3D", - "ldt_key": "18733F13E708B6216C5F3826FEA2A82772B93CD8E2E40B620082DA32683318B26A6D41740CB11D2E7665F7439D4D7FEEF4B4BA31E547F5A917BD48872FDE198C", - "hmac_key": "D5B67686860DA34EDE5A5F1FE0A7999FBCDEC0A7E7F4A3CCA7E480F65DB75976", - "adv_salt": "80FB", - "plaintext": "18D3BB1FEFACF5318DAF518BCD53F679B5F90CA3D245745687A31A316EAD63", - "ciphertext": "DFC2B0933B9FF52BEF254683FE1EE7D4B7248C8573C6267CD0BF44D193D47D", - "metadata_key_hmac": "407CCA730FB95A64283777A363CA3B43AF9478CEAA52BAC4907FCA3B783B460F" - }, - { - "key_seed": "361238F7C3CC6B4CE9612E38AC7B139208DD3AAA50E39AF703D68D83A2C2887A", - "ldt_key": "FD5B076CE5A0B6C5DC5F5EF0C2C7F23685ADBD429504B24ED906D0ECC4B1A6DAB4382532086FE35C9B7378B03D3B69C7DF7F29C9822D9050D3B8F40F0D98D3DD", - "hmac_key": "B8EB344B03FEB7A27A30854515A7CF4DC42FBB2057023321E0A0E1DFB5199449", - "adv_salt": "8012", - "plaintext": "E12A66BD01BC858B59D808EFFFCE87B6FF2DF3712B41A11A9BA323", - "ciphertext": "2F50633541704D77A97363688D071395AB687B26AD282CE39CEEEF", - "metadata_key_hmac": "7DA0CF023BE8C09B06A086C99850D691F832F4B868874D87BA74F50E0ED3457A" - }, - { - "key_seed": "A104A99A4AB90E10ACEFFCE0D51828D25C06EC0966E9FFD9EFE51962AA26C739", - "ldt_key": "A91E76856009A8EDC71E653E4F4A9BC0BB78EC5E429DECA5CA7A073B09FF40633D03487022876EAA6E757F39BDE654BA386612470F4CA01AD9F47A137A190DBC", - "hmac_key": "E4500584AC08831C48B62C58988F3BEA6FC8D03C4DB4E4B7C17D77C54DB63114", - "adv_salt": "1579", - "plaintext": "8E6054C4B53E03581B9B1714BD22593762B165048E54C0", - "ciphertext": "7A48138BA8B2562153E039E2B45E29570F7311A073681C", - "metadata_key_hmac": "403CEB92D349AB8A4CA0A6C8C96760232FBA04C8401F10BE308F1ED364542ABC" - }, - { - "key_seed": "493BBFAA9C6957F17A93E4097DE5097DD63E3EF6BCD1125CC358F9A6B6E1DA14", - "ldt_key": "D21A883029B60B08FFC5D4EEC08ED47EA86578EB50D6812B1928F9FAD1BB2FEF253426A1F7D84913166F76ACF82CF6576555E1CB42D976910B6F92C165A48791", - "hmac_key": "8060C30A4D7DC672626461653788B56B73C2F8C035FD061FDC7817F3523390F9", - "adv_salt": "A1BA", - "plaintext": "3E99E52496E838A70A5B57E7DF237E58DF4557E3", - "ciphertext": "77798A6827527FC66970CCEBD643A08E3CAC090E", - "metadata_key_hmac": "1735F7C2BE88BE734F77043D1F1B613A84824CE21FE0A4CCF1E71550E0654841" - }, - { - "key_seed": "A1A1BC939762245C70223C8CE227B61F3DFD89992E8464F22D3DBE0D498887A0", - "ldt_key": "3A7E084A470EB974216E6180A31E5E8980D9FB5FEE342AABBF41B5F8D6A6525B279A0D5EF8BEA8C315C5B8C4605DF4D69F679EB5419C8E6C99DC85AF6AC67876", - "hmac_key": "9CB48820D7E8D680E256C48A7C7A021DEDF1B7F02B7A9094EDC911639250F8CD", - "adv_salt": "98E6", - "plaintext": "73A7B437A17454C8BF34A1FB582E45A8162E6A36C788565E7948A3B6BF", - "ciphertext": "8BC2F1EF3CB36AD65CDAD1B35388413375807E65AC2416CC68D20A8574", - "metadata_key_hmac": "13164D584E2A4F86A3E3AE2F0DBAACAC9C4164311EBCA4EBC583B63E172E5E4D" - }, - { - "key_seed": "121B7BEFFAD0D37500C1C822E374996E019EFF17838FCEA37D9C58AD30136BC4", - "ldt_key": "5A656392D62FF8F0381F14A16D6441C68B5EDBEC3B119B59FCF464C12CF27606110A296B837420F8570357D3EFE269321B72D75D45C344E10B4DB2C8E248EA2E", - "hmac_key": "B000E9A48241937E4559949A02B8FA78FD46F4190F4297814305CF1A0BD720F6", - "adv_salt": "9759", - "plaintext": "5247E5AEB960892446421DB1015BBDAB6E2392D88E", - "ciphertext": "D110708EFD5FE1C0CC82A34E980923A02AAB7103F1", - "metadata_key_hmac": "52133F6FC1BBD9AEA4805C3BCC76666A03D23EF58A5E3BE81D6A6BF4EDAA2FA8" - }, - { - "key_seed": "3283BA6E329F70ACF8ABD7C63A2FC7ACDC80EBC0E1737BDC65A6B5B5EF5D86E1", - "ldt_key": "DEB59C6003F26311905F0CAD108A9087A736828956EB2F928EF0FB92402C02F5EA94589A0607DFDBB392B26FE9029C1E11AF5E40B799B72397B76A09825CAEB9", - "hmac_key": "A3F0B2459D0B7B8DA6F3961E927D82352ACF411C7EE14AAC215385EC091276E0", - "adv_salt": "61DF", - "plaintext": "628F6FD1578E761FD5AD0AC525371CAC5B41E72677E8EDD97745E46369", - "ciphertext": "05A924C5247E2CC787B704FBC6966449611CA9E5D61FF3A7BF7867F26E", - "metadata_key_hmac": "B31D61D1CEE354952A519E19E92DAAE3ABFCB3320F74672C19C5736CD280A63D" - }, - { - "key_seed": "EF919FA12B5B15BFC62D5586AE1ED5323DF4470782AC548362F9C62181D1C9EF", - "ldt_key": "53BAB9765840DA3CAEBFFD5422146BE1D566D9698920757B1B5378F93447DF2F1F5BAB7E2BEA7A97718F4F1D323141D5E3EB3D1682CB6737EFEE711C9E353DC2", - "hmac_key": "BCA9DA4053E80799C743DE5408422E28F990582BAE83F81FD7CACD9814B5D749", - "adv_salt": "2AAE", - "plaintext": "3C67FF1DEB70CED949A6D210A5D979CFD3227299F03E385E4F415CED374F", - "ciphertext": "C8D8E5BD8F0D49762C35A8D4259C64C35D5C0733CD6B370D9DECAB955EE2", - "metadata_key_hmac": "89F1F8BB8859DC5956FE742C2855EEF0EB95F57C174A80B1499547EEE43E587C" - }, - { - "key_seed": "B0526E489787BD01FF7664E3F8C219A71C3DDA7B3DE7AA4509E6A3B01508D16A", - "ldt_key": "9C9A9D6844FA9678C2F839A339E038CF6DB0A1E028239D67BFDB23FBE84042CA7E1FC8DDBF19B06515CEA2DB2437699CF1F8CFD6C45E896317BEF67F916A8519", - "hmac_key": "0E67540AB6F91B30E6A41BBBF26A406213AE98C1A247242D0113EA3701A3530E", - "adv_salt": "373F", - "plaintext": "0D5EB90F9B5B2EC2647F11762D58571E426A4852", - "ciphertext": "37C284E4194ADBD968FFDF4E966B01B9ACEDFF8B", - "metadata_key_hmac": "07EFB90AC463F9193894306983A81E8EEA260D451B9F572EF03DA6CB5A50D94F" - }, - { - "key_seed": "BF0546F7590534B3821388F8F5961F0554C5138FE4C6D0FB185BB2AB01F7D215", - "ldt_key": "50B0D627DA5633BCD173D0BB243B4CAAABA8F8ED9319719E78FE32F3319311829472C2E5B4B951D7E2EC7F60ECB29A191955A062B07CC7DF0E7D7CC27C478A31", - "hmac_key": "3D87AAB29C200A92B4DB66640ED7EC91C44E7A1C79D8201EFDB4E11036572566", - "adv_salt": "5DD4", - "plaintext": "1118063B217817AA0FE146259D46CE916808710589C01D21EFEE9B3D", - "ciphertext": "8F714851FA0EFE27F18257F518E67FEA494AF899C2843FB485F1A301", - "metadata_key_hmac": "4C279037AEE50554B7C88A6A418415D14471E5D667D66682621B3C5F2C959979" - }, - { - "key_seed": "5B05A47AB82F86E8E555BA28C93A2B5BD3919EC88B8FE13DBC3E000B11BDBC7A", - "ldt_key": "1C4EB7C214F4673DA1D789A054A96081F0D52C064128204C5F39294CF95BF89B42F1D537AC992F23BF40B3BEC22FD2D757FE8B6ECB3888D2A1D171F9B2A688F3", - "hmac_key": "32A5D4ACA2FDE2F18544A0DE369B489F36451E75A1BF54EE2E30982D0EF63A07", - "adv_salt": "F8F0", - "plaintext": "DF3730EF735DFF609AEABB5880EE44FA1860ECFB971C6B24", - "ciphertext": "BCF079AC32C7FFF6C2C1D8F54CAB35EB6B4DAD8C9ECC7DE0", - "metadata_key_hmac": "0588473D41C7197589AFC3EAF61FB7C02C7EA8FBF25CB7AB1241DD2E78F8B145" - }, - { - "key_seed": "016A954E67167DD3C6EEDF2201F07C51A95DB91868753CF2FC4AD3BE0EB58CEA", - "ldt_key": "6D269972E508187094ED221F529A9B6C923BFEE2F35912BBFD3C0E1E9A97F71766A2309603CD63CCB85DD369A30A88BE54D3372100860ACE92014F5194A32341", - "hmac_key": "CFBB2DA33EF9F573C5094A572C408719148B7CF31A2CF927F682E36F025670D5", - "adv_salt": "18EF", - "plaintext": "3C000A877C960594EE99C3F5D8AB04FB5A56CCCB3A0B7640", - "ciphertext": "C7AF1071460C8C732160254E1DEF4766500C37EE246AD71E", - "metadata_key_hmac": "F01F98FCDA25180AB59437E5508422B04498A00F987A5DF890DFF83342CB16E6" - }, - { - "key_seed": "1D45C25E8C05DF39422A8470B062E3D3602750C31BC987576FFFE8F416F6BE2B", - "ldt_key": "470FB25C112AD1E5D5A7C23B028A83A53FD3C0A49C94DC9FEA62A6C8A6B44487352A3084E9E321A92D21FF6B5CDB5BCEE8D20C3B342F1EB79F7ECDBFEF5953FB", - "hmac_key": "66D362DC79BE14FCA6A867D0F57F511097E09A520D2D4661F2AED055429B3D4A", - "adv_salt": "02B9", - "plaintext": "70FE775E7053C4500E1E09546871E8C56C83D4088855C1E2BCF79179", - "ciphertext": "61FAA929A050FD83C356FE82EDC6B256445BE6AAD4DC59AF79C3B778", - "metadata_key_hmac": "19138BB4447855BCB6F5CAEF83590BD64D3CCA580139DC49E642D924860517F7" - }, - { - "key_seed": "4079E48E0C54A9DCBAA6AE5D3D5E1F637BBE715645070F5EC8C6223C099FA200", - "ldt_key": "D1F346CDF8D5BB69C38905FA3063D32C9638D2A68CFA2D6A0FFF2A58F860490DA2C251C147423A8F2F4FCE252985EF27B730E637F5C680935938EAB954AB9CE7", - "hmac_key": "C735DF5B94B8FA5B5A2ADA614220F92C5CF8E0FCA99CB3A4D750E1ED2A039291", - "adv_salt": "A397", - "plaintext": "A72410DD92A65CCC4888931049EC0468E015970E", - "ciphertext": "009257F0EC78B65A8B72E25E0E3215A0831C3623", - "metadata_key_hmac": "7565AF05C99D2EAFCEA91CB916D423FCED6C8162D41304CCDE1968FE408D6BE0" - }, - { - "key_seed": "88A424FD954EBE8DC69E9E30567CE77BB1B53E1E41A50DC4656C69A15F0850C5", - "ldt_key": "4B5BEF639496BFF747FBA58EBC073BEDC5D039F46A521DD2511478751242A90C1C830647CE0892DABD501E1E7BB4A710E795822C6BB20EA2536F0381810BE55E", - "hmac_key": "C6D6ED6C2334032ECF3A7EC2CCCB6561D3C7B537069F036BCB97E07D4479B41D", - "adv_salt": "315D", - "plaintext": "BBF8E1F2B005730BC7674EA7D1DFF3AFF1C5E4", - "ciphertext": "48B50ADB7E937959BAA183739D0A89F4A69355", - "metadata_key_hmac": "A2C6011E155A45EFDF6138F038042164AE016E498A143283691D79C5BE32DBD6" - }, - { - "key_seed": "863275E1E0DEFF0D0FD958E6DC5A3761E147270C8C8F7CAB31A03D4616F58B89", - "ldt_key": "35D4491ACF0D60D7163D9353A2CD150085CDE38B613BE14774CB0BD21D4B1A7424D3A2E9BBE5E7386E471BF0BA9BB952E3AE23A7073AC2C639B73A885E0AF543", - "hmac_key": "E1443390930FE359DE459A8D1DA38B2991D47C5F14F3AC6C7AA030608F579B69", - "adv_salt": "E0AC", - "plaintext": "803CC93E2E79028A2F7296D4FC882806D2B430CFA407631662879C50", - "ciphertext": "694088F041A81951B222EF17CE1ECEB37D3AF87D6B380BA0A70F2BED", - "metadata_key_hmac": "2F435D6B95AD5C0EA3958A58EC6F62BF04971DB04D3ED8B8C0ACB041FCF6E592" - }, - { - "key_seed": "93BE31C376BF990F9B7034BD9F47529F30F697EFECD4306E3696BE5386835E87", - "ldt_key": "0A406E34A9837F09EFCCDC7F39BA22E444BAA886B4DBCFFD4766BAF934C66920D29D7B3AB531CAA4A6986A29919968608610C3DF26C075C8324762AE7FD90B5E", - "hmac_key": "D5CF9D473D8DA0D9A9109B94EAE16476165CCBEA5FD233349E0DE96BDCF8CCD1", - "adv_salt": "66B1", - "plaintext": "0F42AA0A9FAFA18886917149BE8B3C714EE062", - "ciphertext": "CBD82E0A520ACCA985029E0AA1BF189F382355", - "metadata_key_hmac": "19A86C5A7B51805E382AC7708A57726FE77C76BCE55DE91D936BD027BD2B1689" - }, - { - "key_seed": "82F95337DF211FD4E70D1CC2C368AC599A34D09FC0B83F86A3F8B6D6E8653BD2", - "ldt_key": "4BFF8FCBDA91DB38F96E500E2CA2F4579F02B14AFB20D97DAC5CFB0EA36C4BEF68A1D3A9F92720845DF021DA8D2696F3C68C3ACFDDDC5CC60A41A8F312E66C4E", - "hmac_key": "9258C9C8CD52AD8716B4DBD190EDA023D2D4F4D4BA98A5F43A882274B06E2E97", - "adv_salt": "3502", - "plaintext": "ECD5F6E936557169BAEF1A1ED8C502396BE78AC5FF41DF18", - "ciphertext": "3E61F4C2260310F5E7DC3D935C7AE90912ED45CF5F60C8B1", - "metadata_key_hmac": "E0549A2681AD6FFD30EC26541F650A2E7644C78C02AC6CDBC086CEC3F27C845A" - }, - { - "key_seed": "D08D49FF0EC2457AC2B47DD5E076C243DB9CF938EC63EE0AE9F4D0D7BC43AED3", - "ldt_key": "293A8606CD8E064A2EAC787255B00BB3662A42127ED09B32D660B10341754388B53B6F17A7621FF269B27B2B780DECCD11E66633D461D29EBCFCA62748BBA705", - "hmac_key": "8BE0557DA21E1F3B747B3EBF15859841F629F44DC30DEDA8A9A586E5D976FDEF", - "adv_salt": "D0D0", - "plaintext": "B1F527E6C259C2781855C2E1E297A01099C0F80D031705248936BF20", - "ciphertext": "AFAAFA362084E8B77486EE59AC75A7646EAACE5494ECDE40EB4411B9", - "metadata_key_hmac": "B3C654410B5C661BE11298BE63ED92F4650A691D16A7A2C313854FF26E2BA9B8" - }, - { - "key_seed": "521760699E3BCB6251021ABEAA830B1F67DB167D20455B19AD07F24BE483EFE2", - "ldt_key": "3044BB7DD4CF31C278DB63F877A10CB5CB81766AF22CD129896D0D62162730B50ACD56C5063972C6A9BBED8E01DE0B6C7B3F766E91AF73B851AE44B18EF972FE", - "hmac_key": "0213386D6DFBCA6EDD2DB08F4EE70B887F004441A54401FB83BFED71938E67C8", - "adv_salt": "89BA", - "plaintext": "84D603076EC41D5B6BB74189C99D746FADF7A6555D0CAA0B", - "ciphertext": "1C8AAFD2B9737BF33D62EC516EE7FD5BC1A7DB3E2D6DC45B", - "metadata_key_hmac": "CDDDAF18EDE36FFE9598CFA4B20115C8A0791326DC4A33414B4E93B405620583" - }, - { - "key_seed": "11B8B00D034B9DF61299B2F29B03A0B08124D1A937AC31FBF93CAEAA8F85CF98", - "ldt_key": "45C93BA189AFB8E02399E779C4B775E049C9A63930CBAA189FB84E2C224FF1E440B751DA15C380E4FF8C044DB43CE7E833CB096266B3368316F20416DFB57A7B", - "hmac_key": "B86DE2F36332C247C765A22CCFED050338CBD95D514893790EB9699C4203CE4F", - "adv_salt": "DD44", - "plaintext": "8CB48D8D29E58610F7F6AED0E4A214EAE07982DE45", - "ciphertext": "26CB68CC2DC942CE7A89C5A0A78099AF417FFC0C41", - "metadata_key_hmac": "F49A777771265636ECCD5D341AB712955D86171203F789DC6081D7B3397D6525" - }, - { - "key_seed": "517CCA5DBB573E8E9BA3061ABF8B971308A13FBD0AF869F8A5FFB74406E38DF0", - "ldt_key": "01AC8A445ECEE85A7E47397D9E6FDA83D2EA705E1920739FD94C96C82FC50E2E0B0F9DD26E06C2D6622D0488E3D9241D33D70EA125D7FDC901B4355B7AB5E05A", - "hmac_key": "1EE05ABAD13ABDF7324515B027A3703BB156111FE3F7062815FE7CF8364716ED", - "adv_salt": "9971", - "plaintext": "718AB14FCD50872E689F89FCE176581FE2B521BDCB85E0667583", - "ciphertext": "7F1FE50239B5FE13E098D9FA928B617A748A81C01BCD74FE53EA", - "metadata_key_hmac": "BC53EB7BE36084F0E5C03123F9D96828F3182E035A20C877F9B91A837E383FC4" - }, - { - "key_seed": "184EE744A6A2D5F85E2471FB75CE2393550AB2BD625D45D0B626B6A328802453", - "ldt_key": "724A5561CA95F06957A90573F334A24C35C757F0FD6474E377A68B01BDD6D3C99C8569BD9D073BD78ACFA7BC1D49D0069FA345D38A01BBEF1EF566174702F9F6", - "hmac_key": "7155DA1938B23B4309E3A8219151EFE732EDB4B2510E8EEE5331B4849D1A10C2", - "adv_salt": "39DF", - "plaintext": "40640644862F8D4C5F12E848B749EC94C2A07DD182", - "ciphertext": "E6DC4A99E93A734B6096D626088FB5240A105B7894", - "metadata_key_hmac": "4919CAE2BE79680549C55858B16EEDEC91D531A88860BB4FA2FC4B9EABDAA545" - }, - { - "key_seed": "CCE8B060344E2C562C6BD07C3E61D14AB33350FE7C9ECAD8DD932A1C4636659F", - "ldt_key": "4A9A66237239D55FD96E7059DC9C6B21AD9D6BB7019C352B62B210FADF9DD6BE6DE8469E9235BBA9A225A29C3CD82B324019309D93324A14A56E56C31633C4E6", - "hmac_key": "327D980355945948B4673D9110FBB960F5080FFF9E9FE2C0CCCC9CAB17016C3E", - "adv_salt": "6A85", - "plaintext": "F862FAB1CA3D9E87CC9F168CC747A81AF9B4044E07730FA6130909E9E6888A", - "ciphertext": "0900AEFBDE843F82F7B7CB9B80B5B3D3A3C724EEBD2A296C782B80FCA0BC5B", - "metadata_key_hmac": "7A370EBF0C39BA95A9C4D86FC67DF3EA2668DAAE637954A7A25ED2D3E8BB6F89" - }, - { - "key_seed": "BF2D1F6B6E0AC585BF3ADA122F9E5EA2FE0FC417A2318EEAA10237A87E636487", - "ldt_key": "F0C23320CCA42CBA4DF4FE33F09D38AB98EAFE2256937C38D6A9207A43122535133B407842CF2E8DDE687018413C3FDD7E38951EB858060C17CE8E2760220324", - "hmac_key": "02F49A21DE768BE1271597C2264EA7934C062FC34FEDC559E94CC7F2937A50E5", - "adv_salt": "842A", - "plaintext": "ED816815D9A9295F02B02086C743C9C451FDA84FBF784A49FF", - "ciphertext": "FC09320F13D88D9217DFC63256D97D3CC6C324552D06625594", - "metadata_key_hmac": "AC4017FC376EE3A0B8BD0C4EFDAC9C861DAF8B8E2358C04F8D4E709ED2E7387C" - }, - { - "key_seed": "C93683C86F62EE4BC02C6D7492677DE0DD018635FB42ADB94B2EDC9BF2530891", - "ldt_key": "8FBF58A09E057DF5FF33B00DDDF53A1CD1A59F2C79C8E34DB7862EC87849D997AD643A3FDF0C6A6A5C865CBD82CDB9DC9AA4537AA4D97516B7DAB71A4B604C2B", - "hmac_key": "A629688DFA58DC48BC00E9D2551F330CC215AEBE1DD870C1845F9986D205972A", - "adv_salt": "3E7A", - "plaintext": "35C533E05B6729ECD42F50F788208D2B6718E3185B33", - "ciphertext": "9DB621E8B9EBC90FA7C3510FA6BD3D3D1BA260FD6906", - "metadata_key_hmac": "A09A9FECD04BC4BB66C47317538F49657CC932CC25B5E60643DA5B14E064892C" - }, - { - "key_seed": "61A4A878EF91F9EA94C700C94849874D3415DE7440FC15B7884E227D1DC1A5A5", - "ldt_key": "DB3339DDA7CC4ADE9F2988DDAF92C9FC1DB2D0B87750D5435A25C5D0ABE27C4E368FB68D27116DE07A198CC61B3A31D7D0BCE5B8A501C4C59E6025FB848BB6E9", - "hmac_key": "76990316DCE0BE4F8794DBB52842B5437D96E5DD3D49398D63D862F68D1014DE", - "adv_salt": "33C1", - "plaintext": "1DBE8F58098F3A06F6F6CBA2D7A6E65217491783A5D4C59475A7C27B40", - "ciphertext": "E60BFCD9FD955F9D0DB1D524B758490C213971ACEEC48B149B048D87BE", - "metadata_key_hmac": "535971167ADFC167E91D11ECD8422739E7A15FA751BCF173E42557AA1578CFE8" - }, - { - "key_seed": "A298E4B46350537A38408F0FA075D65E8F81E9BEAE562D480FD9664E98CF8F2B", - "ldt_key": "8978D10F567CCEEFB6D0D19D5E72EBE8CBC3053F917EB6E4E2136DF955A492CE250B9B3B3D0107A80D2F68B75D7FF7532223EA174CDBBCFAC9183F9025CFFD99", - "hmac_key": "8D165A6DB03554DD46483F915CFF47001853973140DAE9D1BBDFEBBC56577135", - "adv_salt": "50DE", - "plaintext": "EBB25578833B3D7B24457CFE8BF06B0B382D", - "ciphertext": "033263D9264CB66C088DC9A10CD9CAA1FDED", - "metadata_key_hmac": "BC7FBB0A989FD95FDC28A4354FF9268C726A53E7A759DFD7468077806E1A47C2" - }, - { - "key_seed": "53B80C4691384A1D479EB68CB55772096EEB11CA2E1FA35A2ACE999A7758CB6F", - "ldt_key": "28543FDE924317016A04FA6B43CCB16BA5C97DC322A97C041842549D909526FAD717969B8BFD617C32ADB6C184B8CF167FA25727C7BCFC3E91E18350FD86AF2D", - "hmac_key": "A5EA03BAFEDE6525860E63D548CFF9D712527D1625698626EE30314E78115819", - "adv_salt": "E0DD", - "plaintext": "0EB1D50AABB50EC745AC8A13E8BA0F0E132069F0339C8A6DD7DA", - "ciphertext": "236D656E4FD7F3C08EC6BB93923140DE5A1B12400225E7A0D5EC", - "metadata_key_hmac": "BFFA3A512F9CA607352BE92335D02EE1273CF008F8FE1F1752654D364B2E1307" - }, - { - "key_seed": "0DDD8C420432B91B6DE1A2D6F0F78235B0D551452A50584F07AF5D198CAC8BFA", - "ldt_key": "E8F608B4A2B2C992EA1BFA82D99EC4C6339B1ED050AC7B9D7EF0A4FCE806947685DE83EAE9875DA1445F5C338512E677E30589DA7A8C3684DA48018AB2F68F6F", - "hmac_key": "D26A557AD5FBF38425DEA0760B1E8C5909A6D4B8C204AB95CE7477E531E03354", - "adv_salt": "8B71", - "plaintext": "B048E510CBADC24B14539533BF5494FF49F2C3", - "ciphertext": "2F782D87EBA2E7E9C4A0F77DC590DD19745E58", - "metadata_key_hmac": "ED761A5953DFA5A8FA6A005F96E94EEE234C2ACA6BDA24138C0C45BDE95E1FE6" - }, - { - "key_seed": "FA75CFACB662E891B6414794E0DB2FB4BC655C34525A23CDCB0A2E0E85F0D3B3", - "ldt_key": "43FBE39E37AFCBE9675353529C7DA24E29747C8020570BA3411D8180F73AFCA4F990BA56F70B0F968E9417D7439E0085CE7204D6405BA54D5E13C14D5E34C5CB", - "hmac_key": "4D525776364E2BC6F1C5496BA7870E5546844A2B903D5D755592178986657F41", - "adv_salt": "F145", - "plaintext": "795740E52EFC0116F7DB7BD5E06C941AB40F45B7BF43C30A1459AF3E", - "ciphertext": "8222D51F1133C66F465C178C6E143405550419AEBCBD16F64BC42B57", - "metadata_key_hmac": "5EC58B4CF605F3A8C2BEF6BDF6D5D433479CE0EB89D7AA94C5A31D6FA62BF7D8" - }, - { - "key_seed": "D81F137A8A592F5939DBD29612D4AD4C041D85F97D25A6AF5E2AA0732AD5BB7B", - "ldt_key": "A2C2EB3CD286C292EE346EBA49520957F6E614897A8F62FED22825B85B3549509C468731A4B02A2A8DFCA42C06E80DD7B6871CEE493E874AE3142DB499E3DF8F", - "hmac_key": "D1191674844A540B185E390DB8B54BEA11AA29B29FE368719AB0BE396AA26E55", - "adv_salt": "5790", - "plaintext": "1E0F660610C7DD20815985F7416C0A4FFDB6FB976FC5ADD58BF09A", - "ciphertext": "F976BDCF23C7B104D73C9C0349C2CF39DC50798376D722B602B8DE", - "metadata_key_hmac": "54B3AC82E8C3326BC4A32C28D58978A4AB01E5E565877C9A9BED7FBBC5BE4E81" - }, - { - "key_seed": "433500D60CE472A1B0412C1DB49129E8E3ECCB69DFDB2071BB213D79C032B649", - "ldt_key": "42137CE289F09CBA88A147D3587CAE932AAE2CE51603AE5DD256ABD3A32829ADE7276E447FB47051CD23B5E3A26D0B12480DAF79EB0F67F74221A1B4E6A5941A", - "hmac_key": "23C59E52C6EFDAA59C94D588BD0D9B08E51B28218E60508CE7B2DB8424C6FA21", - "adv_salt": "E058", - "plaintext": "7C9C51B6273C3D129DB1185E63E691D3BE2F34F84FB7E59E3BA25C4580A4", - "ciphertext": "31DA8C38F317D49EE84696E3689DF4D7574AF0AF0935F181EB415359A0D8", - "metadata_key_hmac": "7FECF203B6F8BC19C6220DF71CFEECDB3933182D59F13BB64690DBEFA4905B6D" - }, - { - "key_seed": "AA82ACD315420135AFD50956D58C741AD038C1CB4ADA9107E62C544299E8683A", - "ldt_key": "3A869E32C2D2D0549CB585A85256C24B9E38066B4F970FF221B500E77ED87057FE0A312BE868D9B2FF2AA428850EA878D1BAAD7F8C484786A23ED8574A9EDA73", - "hmac_key": "04B2AC14A413C82D59A7CB32AFF74A1A0286B35C79A84B6433CFE5B547B53D1C", - "adv_salt": "7CEE", - "plaintext": "7E30FA659ABC63016F9475E1A43F9C6BE6F63CFF35D5", - "ciphertext": "7C026E54E258A22E2FB306FAEC611F3A27022D8B842D", - "metadata_key_hmac": "BF8EB548A58FB84810D5F89985BBF146219A9F4B6D6A88976098712D8D14BC52" - }, - { - "key_seed": "AF2BD2E9B622AF968A9E28F2D01DC6125600E2F2C919AE48334A6BB334F50681", - "ldt_key": "D2BBB15D29036398CB23FC21E76B3F290B2B6D8B35A2DA87D822BE554446AC37FF6E1178CAF3D3CE33BFA6A23C7216D21845F4B633DF1D886C27DD7848A00DA1", - "hmac_key": "AC3D67D7B80CF27FD06227DCA2A866538CE5381F6D91C1B4CB02C63D67D5D391", - "adv_salt": "DD61", - "plaintext": "DC0F8D81D76F502DE49B8DA6CE0BC92A4F85", - "ciphertext": "16136543D9435ABCE30BB6697D0724FFA2E6", - "metadata_key_hmac": "50BDA48BDA68014C2B79912CB5A78496F02A7E9F53083E287F5F793F8B56C834" - }, - { - "key_seed": "59D1CF20DF00B037EDE35BFF9C2D81916C24ECA0CB2AF45F8D5D06771146CA25", - "ldt_key": "435B0CDDFA496C3DA6E878E970ECB03199777DB9B550B24593D14B46CA0D4A5C97AD3F24EEAF69713D1DE1978D899E82EAB4582740C87E40D3A886E51BF5C7F8", - "hmac_key": "4928D4497E1B1A6000CF7F5252828851FBDE7CDAE1FF94F120F7853CB8C5AFCC", - "adv_salt": "80C0", - "plaintext": "05E40AEDAB61D3640704C79A414D4A33E1FF26B0330F", - "ciphertext": "299B3B353281727F86451A1AE59551DDEE62DCECF28E", - "metadata_key_hmac": "A871AC9C5D5FE41100F24595F76264299737B9DE7B8AF0DEAD676EF9F5720B03" - }, - { - "key_seed": "2D74CAAE7632991E402C74162D00FC74E2265D4871B4C111EA8BC7C0E8FD2BE1", - "ldt_key": "9765F667EE3F8B8AA71EB0E9C32E52E3B40543370DBACB49426DA778EFC5FE8F686B033AEF2D7C812D372864800466A213B3588F24757C1879BF542DBB8772A7", - "hmac_key": "504E5B2C9489CEF0694226A8FCAD0C8063C2F036237BF8B7F0671FE38FC60346", - "adv_salt": "8ED7", - "plaintext": "F9606202547972E7B5AE3FE384B4CCAE39DB36855CEAE900F0F0", - "ciphertext": "15232259C054006C5E89CC14639C5015827E4D4FBF55C8240E7F", - "metadata_key_hmac": "CE489D80B643563798BE809C94D7A999FB9CA939F5AA5B7EBAB0EAB388FF54DE" - }, - { - "key_seed": "5CD613D109C542459ACA3951FF5F604189ED8CFAEFFA098C20F3ED079EB32BA8", - "ldt_key": "6C0A9F9767AE7955820A782B8316BFAF9C19C0340BEF88EA56BD7183B3AD36EB10E6C68A7FB2F1777BDDCB33061E4EDB2D5D217888E6561A106B7CB4E7220728", - "hmac_key": "57384357B50B14AD37868828A49C736E4BAD95EDB5383FEDCF621CC8EB573E2E", - "adv_salt": "BD33", - "plaintext": "2AC767D3A0758F2A3DC8944542C667E10A73", - "ciphertext": "F570C912A712DC6CB04F265E5BA15EB02C37", - "metadata_key_hmac": "C9C1040E72EA6FB67791E341E6719F2B14CBC1A8548F078F73F3A7A8D2C6FB41" - }, - { - "key_seed": "0A544CD0DAF4EF5DECE34A6280AEFF409D2051AB2AAFDCA7391B39B88C9F4C07", - "ldt_key": "023581D6D30E5D936FA2B412197EAB6EAD5F0752F74E0D5CAAC57A5690108414235CFE0E34DF176ECA8518B4B9A3414466E73A9125DDF7CEEE546561D074EC3C", - "hmac_key": "4FFFD0CFE5B6933288346DED3EADA6F011F1E8BAD400282CEB53C318710C4175", - "adv_salt": "EE60", - "plaintext": "46D08772F5BFED8CC74E63E416166F0870F50E25B3", - "ciphertext": "C243A96B6F5C7BDFAEAE49DE62D0EB20FDEC8AF155", - "metadata_key_hmac": "5BA8DD187189BE60A71EBD4EA87044E7D1459C529B5056FDFF710328ED8FD687" - }, - { - "key_seed": "FED59799667B62FF95C0AE5855BE981A03017356EB9DB2832DC61AD91D09C8EE", - "ldt_key": "F0EF9BE489F809B06D8F63AA60D581E45569B97E891CA517AEAD9D7544992A0D3BF8460DF4C625B511FD21CEC7B6C4299DD8E3D4EC1E6C7C144148FD9286B5C3", - "hmac_key": "D2E7A262787F60E9BDCF746CECC80753BB9AD621C293E151DD338B536FB5F237", - "adv_salt": "A49E", - "plaintext": "874981095C3E8D802B865229B6DE0188B794D59D", - "ciphertext": "4F4D01BF0ADE89BD44EADC09F48D2CA2ACCEEA57", - "metadata_key_hmac": "E65BC7BF3DC8FE3EB2C16B03C8EDF6A40A6EF40A3CA4C25F23D67E95E7465F62" - }, - { - "key_seed": "9F909799C002F7A7BD4D7334A13AF9D6E23D22D045624C8EC6AE1B351A90291F", - "ldt_key": "8819682BF93D0863E6FFBDE350D390EE42669A293B08281C7C79655F440ED73132C145142B5BB4D25876B71FB9DD43CB6563820C61A968DD0E3646AAE284162A", - "hmac_key": "14DB97DD2C418D68E32B59A92725F17EB329D58E700B5629FCAE5DA6E0C3C917", - "adv_salt": "FFD7", - "plaintext": "FB1701FEC5B4CBAFDF5A466BD5F03A8A55", - "ciphertext": "8574791206F55805D0805CC8B55FA27306", - "metadata_key_hmac": "3080E8846D6C5FE00E48AA116A69DA2B2A12A963A5ED099E193ACDA3EA8F85C4" - }, - { - "key_seed": "E6AC538A534AE767E973EE88870C99B895E64C90A4D35DA089BE222A1390A9A2", - "ldt_key": "EBD509985542019467D4D2DD645E75A85510D3F80F13C57A2A3A93136345C1BEE714564F63D1B8A6ECA4C5441AA65F3FB90260FCE0CBE0D71A83F6487A935F7F", - "hmac_key": "E9C658B89C127FA335B5288393338E425B10D91B0A6D2CDA3201E937DF005089", - "adv_salt": "9BBA", - "plaintext": "D3D8FD6F5F87E6495A1074BBF96893DD0FDD4D4AC7A646D71E6032A940", - "ciphertext": "811F782FCF532B8CE2DD7D9BD4FD2E1BC53F3CE766CC806F5C22EA845E", - "metadata_key_hmac": "81ABCA37FBE03E4A93BAF5B39E1E3CC0C5B8860CAFE27F2A2DB5941901151A18" - }, - { - "key_seed": "318829968E74DAD7AAEF1E0A38B75090BBFD615D498BB0D3329895B19A99AC0A", - "ldt_key": "DC38FD22761C2AD95226DC62E59DB6B4F2A123E8B7F0B051190AD15A3D43FA615CF7EF343F9C71ABFA7DDD82B11B75F8A6C9CC60F637195E62549A4F901791D4", - "hmac_key": "110B7F59B772E542CEB985D76597C3292E203A8F07C3B61BB16DA496A29287A2", - "adv_salt": "6828", - "plaintext": "86EE8C8CCE12728BDD3F1D4981AAE9BBBBFAB9B0AF19268B1C76D5", - "ciphertext": "5FD08415921FA4EBAA96E5AE431046A5EA303644EB697E0130F296", - "metadata_key_hmac": "F6DA270AB6BC300455B1B8ADF4E735D9A6424F3483282BA3AD7C6E5E6416602C" - }, - { - "key_seed": "280522A0E9A7D6B93559616E459677950385E57120976CB16143ABCD016B462A", - "ldt_key": "8DF52AEC6B9151A538696F1A6D5C909B183EE5ECC965FF857E23B2053CAE6BD48A9233AA15168E1FE6E34BFED7C08A5143250C642F0D315D2BA3D6751B4CBEA2", - "hmac_key": "FF0DE7047DE672CDEE76DA1F2AB7A4F6037C8056B87AFB01D23775154CFEE49E", - "adv_salt": "D224", - "plaintext": "8654C8C1662FEB3C4081908308079B533C6EB7C482", - "ciphertext": "77749830BB6B9368783A0170D9A09923C0DB7215AE", - "metadata_key_hmac": "2965D442FCD5C276D98973B74C2CD551F5EDF365691EFF05DF27EA21570A8AD3" - }, - { - "key_seed": "44E769CFDE90D9F3EF56A653F28ADDAA06B2CA60EC7FF422879ACAC2CFA46111", - "ldt_key": "BBAC7B253EF46F3617DE1B9FAC5131135F2B213AD6A20ABFE422D9CFEC5EC85320DC4FEA089AB4D7DF679CD2507B9BEFD3A86468BE9E3929572F684AC6A320C3", - "hmac_key": "E41BB366EA27E78220208EF81F75CEF9F6E462E5C2F981EF58811C60B9663499", - "adv_salt": "3D17", - "plaintext": "A155D6D26B2F127E2FE82378B341D2FDEF3E16288ED7D3F3AC60", - "ciphertext": "8EDE7296186394BA203754260F747EAE8360480CCF21D0B6DD8F", - "metadata_key_hmac": "74009FAFC9FD260F001569709C4295991C242B5A61E6757AC708ACC3353CBF5E" - }, - { - "key_seed": "AE66C35F7D04021A5C698C352F4F0E9D6BC341054228F6FB9244B777C31779B4", - "ldt_key": "AA3F95B3A0E64A2C4C92DB7683E4A9FD6B5CAB46650C09BDCDECA9DC8767BA9813814FACEC94CE675DFC3550B238A069CD1C575B43754E86B1C2447647D31FF5", - "hmac_key": "FEFFD7822CAD0ECD152DC7D05BD7E928F97500EE40995B30DB922489213180A7", - "adv_salt": "7B92", - "plaintext": "84F5E66A4A74125DBFF956A02C3803AC", - "ciphertext": "D3DB7D16AF86E6BCC2B517D58648875C", - "metadata_key_hmac": "8E2F1AEEB263AACF0282E9769916C5A265CA1F44BBBA0987D828410A1BB12321" - }, - { - "key_seed": "35B9E153848ACC7A635654570B9383281080B8534BDBCEED1603A6F8C6D5507C", - "ldt_key": "9FE7252B04B742365E177DC551968D561DC229A579D5D300DDBF64F5AC4972CB1F68E04B547E63497A5356B34A34F73B1202BEAC45527423DBB839D218ECD30D", - "hmac_key": "2B95CF79638C004CA750F26A19226A29697D1FAFA2B4F3BF8626F8678861C13A", - "adv_salt": "6B57", - "plaintext": "35AC4FF891D302D09A2FF9B0D79B690BB2C1C3C62ECB8CDD6C9BA116", - "ciphertext": "9CF13BABFBD80C501125B19AD377B6257191404D3EFE5B41D9AF7F09", - "metadata_key_hmac": "D3C52F6F990063859C79B0D3C92210DDD4B9CE9F15DC889CABDB87F3613F733C" - }, - { - "key_seed": "687532B1C30FC1EA07FC5E016895C91E6AEF0DDE518672CE737BD4DE49848C7B", - "ldt_key": "1F338AB5C464BBBDB21C74CA46824422055F2D936E5C8E7CD9D070AD2B94D8C2B143BE8ABF4E5011B550F36C702E4355DFB2E2790B3FF94B77BB8DCD66EEBD4C", - "hmac_key": "00AB3E77B01DDBFB63C0DAE4F3629D1D36DB38A80CB9EDC6D24D48A9FB2C22E2", - "adv_salt": "3CE0", - "plaintext": "CB64C632A684EB164D597CC76A77D37DAEB7BDC3CF0564E4", - "ciphertext": "CC05C33E64E9070A0BDDF3EA43B3E07B20ACBCAF7887252B", - "metadata_key_hmac": "DEA7BE9F28AAC7BCD020EB419A7382896B6F326D3EE31AB8CB5120FE17ACDCF9" - }, - { - "key_seed": "1076CF7AABA9FE8F884DC407AE488AFEBE10CBBB638D9F30171F1FE11CA9E490", - "ldt_key": "6954D32D9BE52A9FCA5868AF05C31E99B23AFC57F35B5B85BF85E881884B6B0B7925AB1AF21C6F0B70D139558FEF434DC55A42190EAA5DED0903A99D101A79E6", - "hmac_key": "EB95583262E1F170102BE84FA40A8602D81FF7F4284A81136BDA6C44E6421908", - "adv_salt": "083B", - "plaintext": "AF30C1BE220AAFF63753CD60888CE865C1AB3962C7696D60", - "ciphertext": "49C25447783F57672C331C9CC44AB38BE9E7C08BEDB25E65", - "metadata_key_hmac": "98D61316118887FFCBC232C0201D97C1B6F1F1208D46786349031081FB736851" - }, - { - "key_seed": "E540DBF513BA5D1D660FA9BB7EC880B13B9525D415909172C4FB6449E1091C3B", - "ldt_key": "641FCED17EC3ED765FC414C6310A994E141E97FC01674C04F5686D48D33CBC92929734DFEEEB95D0461AE32043900D001DFCE6ECA701D9355AE713CDC3FC671C", - "hmac_key": "44E3408B3F701FD8E22D0520B7B5350A7DE5623A2293AB3DBD4EEDE8C06F805F", - "adv_salt": "0A21", - "plaintext": "DABA28E713234BC8A65B5E6A9876EAF443985058E704E9D5E6", - "ciphertext": "C8D35138CFCBB94F1728BACD1431A53F443715333D7EBE1195", - "metadata_key_hmac": "322E76085DCE4370101F0FA295B2F7CECA5FF72EFD74A8A5D36F1C86ECE65D9A" - }, - { - "key_seed": "1A0258CB8FFCF6B1A4060754D79300B678395BECF87F7B291A81660A73A45DA7", - "ldt_key": "F74BAB65280D7C964EE58219A8B03699D2B8B3836466698BE00264EA10D5193BB2193858AEDE740D559D60B0016D21F85CCA11E006D9587D5A56813363ABEFB9", - "hmac_key": "7E74C500A645FE5992A8F5C72156B7A8E7E35E6FD8E24CB5B0F5E87ED928C82D", - "adv_salt": "C93F", - "plaintext": "A4B100A7F1EFFE4CFBAED727B0116008", - "ciphertext": "FB3F0705BB236C87E99D98FD7ECCCB2E", - "metadata_key_hmac": "B281E7B6C8F510047D3707C84FF05AC1B7DA7B6B2C90AFA43977608BC889E3DC" - }, - { - "key_seed": "CE96629C4259457DD42183D24D651A0954568EA47DA08BA41540665D74592BB6", - "ldt_key": "13224342818872CBBDF1EEFB4E7260DD673CD601298D06705ACB56391FF6FC44B5F4F2F38898CE23538152192F54C9B89B9CA8BFDB6D144BEF24777F0D469DC4", - "hmac_key": "C77A50FB84F7C0F35264E697CDD070AFC17452B08E5943A6F98A59539BA5AD67", - "adv_salt": "EC98", - "plaintext": "CB57670713089CA8EDA983C4C0212DC1F699FC0C6A5B", - "ciphertext": "28E09ED5045AC92F7E08F62283908CA60C4EA8558E77", - "metadata_key_hmac": "0B714038F04BAB7ED853780BDE53496BE9A883CDA8EC4B7CB7BF2E04E62C6790" - }, - { - "key_seed": "8CDD9F5539AF7EA7ACEC71C0D43CDB1B3358F7FFA7AF5DFB77C9796F9D108830", - "ldt_key": "02123AE1B3033A2C4832936464714F4BF5DC16D641839B451FA99ED98076909C258244FDB7384361991C27FF34ED27B3C93AAD0E22B6E6005CDD7C8794145F00", - "hmac_key": "9AB04D6FF1D83EA7C7D987F19595F9E3037856B3EFC34AA74C30273867850549", - "adv_salt": "D034", - "plaintext": "2FE3A1A36EFB21407D313E64C8BAC756A1", - "ciphertext": "89CCCD395B9BFE3C0BA49F9B9DCB529B1F", - "metadata_key_hmac": "C89507EF56672FC994F5FFBB93F099534D3201D6FA97122FBD5D2FF279525C0D" - }, - { - "key_seed": "F3CAC3D370DF389BA4E949320C7AF35347CE90B39864EB28F1BA7325966163FE", - "ldt_key": "0FA705023E801CF9626F0B0B29446A1D5E3B7EBF8DC4228535565F8096D5EB374061C6AC89AB77F8FDF15209A49DA4162EC3A7731B695C8BA97E6A6A54AD927B", - "hmac_key": "94509AEADA6A469B8AE4A4CC57771F386F4FEADF8E073A758DCBDB484C9C1472", - "adv_salt": "B505", - "plaintext": "C9CEA0BA6FF74A45345DA313F27F1E78206741AD1BEF", - "ciphertext": "458A3FEA342BCFA9563FF419CB1C11CAAA18CF74E4CF", - "metadata_key_hmac": "3EDF761D6F862AE3C4D6AE1932E5DEB75DF16D060A3413F3160B859EFC8C2335" - }, - { - "key_seed": "90738CB1AFCDBAC6A9A01C668340AA0C5E388E38F4BFBBDAF3A2F1E4D00230A2", - "ldt_key": "D470FB6A06FE70104782740EB5C10BAB3C19AB59767C5AFECE2201E433DB125D2D4C5672596242445D829EDBC89019E2AB449E87C0A9FFDF9DB15C228D7FA643", - "hmac_key": "24C9F3B88BE8BFB2AD54387CED3DBA80B470BFC04A0F1FC38D3C1D818247251F", - "adv_salt": "14D8", - "plaintext": "6938B0CEE011BC98046AB7D8D906E9272A9A", - "ciphertext": "5329FFF7838E166A72B5264D9426BCC777DF", - "metadata_key_hmac": "D58E27099B581E6357CFAEB8FDB74750646C4EBE1BC8BB756FD7A2112482C12B" - }, - { - "key_seed": "E167A2FDD3D194B125091811557C166B51286A0EF07B428ABE7491B1F7D4B95C", - "ldt_key": "A857775D84E7E944A0D8646FCC65A1F68D5F9416711926C426DD13C870B345AB51D5F5C67602E326A52C02AFE1AEEEEBA6FBD5B96DFC684FF672BFD7D48BC0B1", - "hmac_key": "A13BD102F4DEAABFCA6A7EAE6A8737CF2003BBEDB67636733A8FC1B477D7578C", - "adv_salt": "D1ED", - "plaintext": "4D2D74C7B1FBABC53F276E2054229FB59756B13BF8", - "ciphertext": "C8DB5D3877EC446D84D2D4C2F5BDCF725F573B82CF", - "metadata_key_hmac": "FE8A0D0AA4586C3AD93556FD260ED5FABEB0BCBE21B656A09ADB7AAEC13873CD" - }, - { - "key_seed": "C2D55EDB8F61B628A694759CD39B5DDF3D0AF8D728654BBD7E2EC1641E30D584", - "ldt_key": "260CE6B2300C74F630074B946A98A12196EBB271849396523E75C777F5580AE4F853E7C462B1C5E95C14BF910EF567E5C72D69DAD21372EE79AD1B567D0673EE", - "hmac_key": "AADD4EFE6EFC77D76690E95CBBB7F9D8FBE78DB96BE4279099933431CA7C0CD6", - "adv_salt": "549F", - "plaintext": "585C510BC7605EACD72E32F06C634937A2BAFBC7780963F371", - "ciphertext": "BF2F3C7F84088E8F718AEC12C03B0EEEFF0954262B98A8239A", - "metadata_key_hmac": "1A5F73FC9A79547EE81832EA25B3C13A883CE2E1F6C9B4C1C8EA00A2C5D402BB" - }, - { - "key_seed": "3B1DDC15E0631966EAA4E68F314DECB49E0A08F2620A4AE7B824D60181DF3BE2", - "ldt_key": "5B03B2A87E537B8FE4B0C0898FDE2478013225B121F225EB23998694073CFB1099944096368B5CA7E3750A0E12278479FB336155F4B128A810DF04A100486A73", - "hmac_key": "31A368D150A45F2D2A61AB1C1A10128AAAF46D1F6C55F370BBFF9894CE0C453B", - "adv_salt": "0B30", - "plaintext": "D01BA2A3D3791D476ED7920D9C8C9FB59CCB09D9726D81B18103E7F53BFC", - "ciphertext": "13FDADB34B3EAEE768A31FDBBECDF1B9D803C5A0F3503E66C4DDBB566A66", - "metadata_key_hmac": "10F474C052FD27D591BE50A2258F749AE1C322CF31A577F601ED10AC92F0BCDE" - }, - { - "key_seed": "D05A40EB2A490AFFD6C9080FF0B246CD746D7EEB1AD5A989D2B70E82AE1AC245", - "ldt_key": "7AE2D1B2E56E73D68FB690A93180C30062CD08506A455D5940D7C0101F03EF48B91077465FF77AA0BDC56F3ED4619D0A126A2C19FA77315F24FC42CD56AF712A", - "hmac_key": "D26C90D9A22DFCB2BA4DD1C2FCF846DC6D34DBDF5928AA0291FC86C38BEE70EC", - "adv_salt": "878A", - "plaintext": "E41F56B7469491404C9085AEC86C8E818D", - "ciphertext": "791714106233445CC920E4B5E04BC78800", - "metadata_key_hmac": "850BF2B0F3F4E4A20CDD64DFC2E451A636EE3FFF64CB58D035647FF41F316127" - }, - { - "key_seed": "C1D8FB7C8AEC3E472182033DF3C22486D85D0AD814A4E66ABCCE536FB2A809F8", - "ldt_key": "86A0CD0A7892C19CD539045D406101699423BE2E09C0602936C03ADE82202CD377AEBA7C13E8252CEC8B7ED2692F9F8618144C117E3EFBDCE16C34B03EA181FD", - "hmac_key": "975C3E0F9F7A935042ACC888C27BAD5B372C5744D8A70886CDB89633A947F4E4", - "adv_salt": "E796", - "plaintext": "4C632A0EBE20C353422EA7E6BECDF2187061E47B27D00FEDB5D237B79DCE7C", - "ciphertext": "DFC203F3CBB6BD68737632B76A889FC2B4137EABFE15FF0C89AB78226A4DBD", - "metadata_key_hmac": "6005486AF7B630BA2A910C872F84005298C66ECA82E52646C719B42A6E049ABB" - }, - { - "key_seed": "7421221A0F0AD0E1E40B807C29FAB0BD3ECCE688A7AEE3B80E758BD19D4D59B4", - "ldt_key": "F455AFCDEB473EB52482C1B91CCF1934B6F88EA0E730EB9F4D0C0A843DEE28913E20ACA037F0E074F1B51295FDB94F3B5808A8D19CF88BF3827DA2838830FCD5", - "hmac_key": "AF1A1D886594E6245C51D04FAF0B6A5806D1E9B43ECFEE7D49EEDAB531BE6EF0", - "adv_salt": "E14E", - "plaintext": "4601A3D31452D93823C7D559AC189AFEAAA9F088AD02", - "ciphertext": "07E5F4AF8FC2C0EA45D1D2B87CC41992BC7D296D0A43", - "metadata_key_hmac": "D7DF9CDCB61C8C362994DBB895FA97A7D5D072CC203F4BDCB28888E884F1A4A5" - }, - { - "key_seed": "2CD8CD00A308856401C0145E13A9CED9CAC6EF683BC3844AD943D9A5880D87B2", - "ldt_key": "50B75DBB72D50FC8855416F54131002F29B443DFAAB3B04D65562AD79E52E983D452359C85809D9CD5296D36E0C961A97F0903623C3BFA8FD83AB405FAD1D7A9", - "hmac_key": "30650BF4F161E2C0C3889466CE63FA9873EBB8E3ED44FDA2694DB232ABA80097", - "adv_salt": "67C7", - "plaintext": "FA83732566D4C7F669E235EB65395E9EA20CF710182C1C91AFD56E4F", - "ciphertext": "D5FC0C956FC70FE612244BCA166E0F7251B4985FDCE2EB37ADB9492C", - "metadata_key_hmac": "ED4DD7A65B7A9395E06046252B259B01E4FF4DAA5F31E3B4C887CEEE8BD8C422" - }, - { - "key_seed": "961EB7E66755382EF32B91C881D1B370CE8C84472AFAB8730CA72431CCF5709D", - "ldt_key": "D20A6B1DCF00991DC6428BC18539DFB54CD4C7139D174D279A184E7124921E52AFA8203AD69E8C344F8DE98AFF20A46F7ABD784FBF7282CE8E2ECDDA130C0616", - "hmac_key": "BD12138D7A6759FE88B57A2ACAA3C2AE059FD223A7F768FB14C92247480F45F0", - "adv_salt": "6127", - "plaintext": "C2EB434C6012DAF38B420B10886DD4FD0B4F47A4C46248B3647E9DD2FF1337", - "ciphertext": "68B23472CC617EE2524CD544553E372A4073943EC98578209189E80CD972E5", - "metadata_key_hmac": "85B4C89F930106E07EC02C74C6C9A367FBF755D81C3FF360D4DA4F29C33EC151" - }, - { - "key_seed": "EE97B09C86EC831939381B61A2BC9A8CB54D7D6687F7FD500DDA53C04504C400", - "ldt_key": "076C50D225AC3DD54E785DA9C10B29ACF481868A590D6E11458A68253039E32D99FCAF2CBAD329909D411C329C0F2BE7B03E674294BC983F5B1EF24C1386734C", - "hmac_key": "C602826941014B984F279A3BC71E938B0A2441520777F9CB904D66F4FFDD2686", - "adv_salt": "4707", - "plaintext": "07B02E871111A6AF85CAF0CBF4D2E2A6930C405F535641", - "ciphertext": "31F1B4569BF4830BEB16FF2627E27CAF73D100241F2D26", - "metadata_key_hmac": "3A0B7F8E3527682993B7B168A8B6C81C16CC6E41E90A2395AF25BDA99A9DE9B4" - }, - { - "key_seed": "90B1F3C4E5E3563776576A41F54FA8F8FEC39ADEFD7151930A6F71F5CDE1EAAC", - "ldt_key": "23F9BC3BCF20BC098A85807C8E645196E4414E7A1087752A0E5616F59ECDC1BD6A773368D51E6CE75D1BBCB761201BC127F1A7A23C6ED791DF3BBE39C2498A99", - "hmac_key": "97A26BBED95B16D4292F5191C6A7B24E2AD2A2A1185BEB3880C0168578E8708D", - "adv_salt": "A852", - "plaintext": "4E97A89CCBA3AC8D5C722F06C6DBE3AF7F068FD7", - "ciphertext": "0887E7F846287FC4E1533DE351FB7806C036CA89", - "metadata_key_hmac": "F60321123B682D9E8035890BC2F00EE7C263CF198DA707B639306EFBC7F4E625" - }, - { - "key_seed": "E0B3093E67FA08DE9808AE03EADE5A2F6C52C64E6C1D24D209F8BF01D5C3B216", - "ldt_key": "71722699582831C8E407B0E8C2D55843747E180920EBFC05EFEFF2FE94C57B9514F196E6F8C837831580F721242E60232819BEC77C50E4373070D38798CB066F", - "hmac_key": "A8FDD59FFFEA81F66F03E18071954CBD48697DCD56D61B38DE5F0295B04E0A76", - "adv_salt": "CECA", - "plaintext": "C228D2B9F0483026D26010ABF7EEB54FA60FC0BF607F7F3C73721757C13AB1", - "ciphertext": "8DEDA4974DEED69DA408D36C85AE1753DBDB8E57DE92D6DB419C9DA4C359DE", - "metadata_key_hmac": "78EEFFDB4E52ED95F569AFE6CBEAF1152BFDE33FA4082FFCA081B50E1E1EDF59" - }, - { - "key_seed": "3D0BFA5E1D7958861EAC95B30C156F8DD930F2782F53E5FF949A0A403B423DCB", - "ldt_key": "C3FFE404D89D676A1914E50DC99A946AE7A7DF295593617A8C57B75BE73C5633F9C6511921D17217BAF92FA5561548031CEC00B060C431A5614E3F4BA52F089B", - "hmac_key": "70A971751BFE0E714DC85968C09FC4DAC29CF9142500AA4BDDCDCEC85DE0C4F7", - "adv_salt": "CC21", - "plaintext": "4832A069F8CFB5B21FB1D82E7CF9BCB42FD58580776795935F638B42", - "ciphertext": "EDD7669796B5D75F82B7FD1463DC1ED7FFB188ADE2DB85B2F46B5941", - "metadata_key_hmac": "1456E2336700FAC9ED4BB80EE85CF82F70A1A3BB72CBC34E420A17CB7F1B1A92" - }, - { - "key_seed": "BFE9774B7CD737A03FA3AD280C1BE486CF0C83F3CCF24DFB01EAB69DD95CD6C5", - "ldt_key": "9EF46C8221647475DC974309BA3DA5409AA911207CEBB303E47639CC8D6B9CF15653B9676D7E93ABB82ECA46593156BA08D25E903417B1D221D1963937DF5A24", - "hmac_key": "E164FC152DBA6C35F277A5924A156D25FA10099DA607E318A43447B1DDBD0691", - "adv_salt": "F508", - "plaintext": "169FCF6B075E8AC5527E5B632EF377DF7745DF0229B788664B52F0", - "ciphertext": "67287D2CD908E7A0DE65253DA8B6B9010AB975DA5D97E0E85B3E69", - "metadata_key_hmac": "CB23A8B0C9823C44C095FEDF0BD001EC65C33FA0CDB6C3A27835527157195F9D" - }, - { - "key_seed": "FC1B9AFCDA4B0DE4070B4865590D99C1B51AC16013F746F726FB00FCC490F5A5", - "ldt_key": "3DA1E02171D7612CF8DFCE3164158ACD84E53B3A798CC6E211D3D8E3A38796C4E632B1DD1C33939DA0191C55D621CFDCA72E21F8DA33BB90A71AC58847540930", - "hmac_key": "FEB10E4A8F5B536345299B277C636AE33EA21D4906D32B517FF9D84F86525C03", - "adv_salt": "FB2F", - "plaintext": "622025C907045A293B6927E386B727F592388070", - "ciphertext": "E68F9246E8E9068958F10322F77B066EBE0AECBF", - "metadata_key_hmac": "6FBC0B2F408A933F4147485BF8C1EF82C734AEA63E586337F6BF789448EC8AC2" - }, - { - "key_seed": "82DAE4924C598235701F58712FC1EB2FF71064EA21D77A497ED141C4739945E1", - "ldt_key": "CF5C7363836BDAD761955D40A5F4D2603D6EDD0929DBA92F13DF876355F7AAE043D41D3616047A03043E87DBE3025AB6A9244F9A4CA23DFC85FE68F45537458D", - "hmac_key": "7BFF0CA343B4922CBB930FEAF6383D3CED9B2D82F5A20563F5D7D3D876881BF8", - "adv_salt": "7048", - "plaintext": "6FAE845278FC72DB91A23582318ABA051A6593DB2294", - "ciphertext": "62821D5B511ABF78E0EFEFDEF3C1B9D077C488E94F26", - "metadata_key_hmac": "B46CEB074D0DC925BD81C0A9C42DEB23FD601D9CA19D751B9DDCFBEBB477C828" - }, - { - "key_seed": "AFA2295B197A4F7B02148083E172EAC8C990D103EE110E5FD59D46A63E880A4C", - "ldt_key": "706F784A5BA178B15D0E73CBC5CE3AD0BC2D804AEC44C80A6AE7AF3826884F1DEDD40069E1EE47861D1FA8F33E810D02CF1056FA35837B1D617326DE56865CED", - "hmac_key": "9B460C083DB1DCE94932C59CDE980C91AC6DC325D27C6F58DB472B3C73C68A59", - "adv_salt": "33F1", - "plaintext": "DAD0F021D7D6EA6CDB5727BD07A47772EDE47AE057", - "ciphertext": "41703414EA3DB54FBF51F8B683F251A390B9007312", - "metadata_key_hmac": "BE86C7E61CF3E9B69CE5F839A383D0BE36EFAB76607CE6A9E114C23D752DE7A4" - }, - { - "key_seed": "E77B0126661C7427A10C7C2DC888E3588499A4E608312189131652ABEF068378", - "ldt_key": "7C87B6BE29EBFE7C98879A755A4961A92CBECB276A4D5470EE270E0B39A6498CB605D254A3F51C9B050CEEB26F612E1033998A8A41ABB945F04337450E03CD62", - "hmac_key": "F34D7F614979EE2B0152D10561A8E8E791513D5CCE2715F159F472793BFFD6B6", - "adv_salt": "B04C", - "plaintext": "EAE41891217622C50954AEB273E5D1451A8F7DD53436A234", - "ciphertext": "1510060D88AC5720279401FCE44F6B6D669DB022191DB4AE", - "metadata_key_hmac": "6873F823783696ABCEA38DA650785FA304F9B96459280463F9889974AB4F318F" - }, - { - "key_seed": "49CDECB2F2B9B4660142A86CE287EBF3004E94712D109EFBA6B7D32A3DE0BAF6", - "ldt_key": "B14E48697D6C005FB9C3E40B2054FA7252B7367E5E2FBE288858338C455DAA0B597DD27CC8E889C110549C7F98B40E93FC3373432D84F64C383257693F4CDBFC", - "hmac_key": "BF3A3BA5CFF8C9FDBF352704520304ECE0B2927D49EBB6E70FB83270C541F934", - "adv_salt": "0257", - "plaintext": "C4C77214ECA31A2095CDC93B97A4859FEAE4EC057E81CA5B1B", - "ciphertext": "4D69A78B88829AE1F21D402F00098D4D7FEBF07BA8FD4EC570", - "metadata_key_hmac": "7B136B9A716FAE1B92F66C418526B9B4606017CF0888A3A3709D0BF367B0BA15" - }, - { - "key_seed": "5EF26FDBCAC90F504A294B0C18D077ADDA6D28BCCFE9E6D9E1019144E63E82C4", - "ldt_key": "4A2C98CB7211C55079CC9F33E150DCCD00EB7E1BDCBF623A1344C341D733B71BAB51FDDCB7E94C98B83C736F501C39E383AF7FED8C7E24575445E0251688B71B", - "hmac_key": "10C7C6D54416C6A4B9A016200484D256DFBE3238E3DE89015756219CFCDBC9EF", - "adv_salt": "6012", - "plaintext": "0EDBBC19BEF8ADCF812FFCCDE89FBDF9BA2734CCD97570", - "ciphertext": "0CF336739B9A76887A5CB3056F895DA3B071B6942735B7", - "metadata_key_hmac": "59335C71AB60D82F6CC8C7439BE3442AC17E3756CA3F2AC0C0F5F3C74C975BE8" - }, - { - "key_seed": "ABB7CAED17658A7808C8D1BAE9BD851BE8F6B3E0417529F717CF7544FBF19CFE", - "ldt_key": "77A9EBF2D3C0ABD4762FF5404627CF0C73ECA59308C36B889F391E49B36AEF94C12B7C6B594261F94B217AA4D0C9B91B1ED382614245C4F449150C82CF39BDF9", - "hmac_key": "FA4707B6E99215DF51D4A1B2A5CE6BBB2BD820A0AC3C7D0223F47A99B3789742", - "adv_salt": "70EC", - "plaintext": "F4D6F632628DE2A5E863916255D5C91D", - "ciphertext": "92B542A685DF2636F0CDFAE8170760B0", - "metadata_key_hmac": "0B1D475B89137AF6861E8F5BF2C3EE730665A8905BA670E892012405E2D316EA" - }, - { - "key_seed": "D6E12F6F00FAEE25269FF1ACBCAC2D63CF6A7ACD0B12A11BA84BB00F259F9E64", - "ldt_key": "08F4FC8579D835028A44BA9B384DF30CA5442C46F0E12361AD827D966B50C9FCEB7273C06AD0D389E634A6FC42DE00971F582043C43019EBB8C180957FC1E502", - "hmac_key": "78251AAD644F9D46BFA4FD665DC4E0061B6443538E064D1337C6B80372796351", - "adv_salt": "D06A", - "plaintext": "6EB100EB8083DE9FB18D83D89E321FECEF1E116C92F156457B3FF6", - "ciphertext": "A79B09CB86570BAEE1A9BA8FC3A54AFA49D5315092A35AB8B40E02", - "metadata_key_hmac": "158DE0182C312D6AD29C85DF0CDD61E4B41283339D33F44F71BB86F39AEACCA9" - }, - { - "key_seed": "33FEDC3705F223EAF65C20AF5859C6FE4BC2BE03A76FD233CB3B3C755C19EAFF", - "ldt_key": "73832B0FBC059019CC3B69B7C01402297899803228C3BFEC0FEE44E4A8CE9362127FCABEAB35FFA99E53E51CEAFB52AA2ECDD98DADC68E11FE32B2B691141B42", - "hmac_key": "70BFA7E804F711750BD51A8ECF716D8828F34642C8718F3BE3AF04BF45D39E3B", - "adv_salt": "CCD0", - "plaintext": "83A3554F5BFEBD3AA5CD63033F1F84A188428FCE31E28C7B", - "ciphertext": "F61245C747B02E8A31F20C5C418C100779F3304C4BF35D00", - "metadata_key_hmac": "E42B1FEF138C0BD47792602506037A6B6528C6396E2C25EF759245D88BA9C4DA" - }, - { - "key_seed": "B8FB96C60B745FF482A56D79AE96C2011CA53EE99CB4EA416D2081341AF6BB97", - "ldt_key": "5281D0CBCDDA4B9CE9649DD4C20CC65D21917FBF006A874774CC9BD2BE5DAE538E7AD25C7AEDD24D25255F5BF4335C1C7101FE475530BEF3FD34A599686A2EB1", - "hmac_key": "E5001573DCB0E863FEE47F4477AF9CF601C1488DBC8B18A1048F10F4C2DF96B3", - "adv_salt": "739C", - "plaintext": "4C01C0FC54C46EC894E31CB7A3921E4A1C61647A1DE7", - "ciphertext": "078A0A557B03E5B08D34CC068A228BD4076C35784D62", - "metadata_key_hmac": "5E65DD3CA805C6592404472BB10A04370D4E9BBC131E8D91F1E8EC7872C81819" - }, - { - "key_seed": "3E336BE86F7158546D178E5D3745865476DE850174E4EDF93C225CC5B127DF59", - "ldt_key": "CAAF5ABD33E017967D0F86484CE494E76A00E7FE1D481C851133C9711B95A4C397DBCCA43DDD69A90DA70CF7DBC9C86385244968D640A93AFB1DABB14A017712", - "hmac_key": "A74F14F57A80A12D95CE530A4CBC0443F9A6BAFFCD0E401183134C773E3A19EF", - "adv_salt": "1EE0", - "plaintext": "BB1B2619872088EA0E3D47536E4AFE08E66B", - "ciphertext": "0550A3CFE54B801588F4B99477BF29435529", - "metadata_key_hmac": "CAA1272218E865B040AD16B0CC155CC29003372C513D41F291ADE90F32A7E2DF" - }, - { - "key_seed": "C5304C20454F1AD1EA6F1BB2AAD90C32B21BABF043A8CD5F8AEB5806AF9DA30C", - "ldt_key": "23A194FA43C5CA91E5CBCF05C0729568F3E0374E2DEC7D124973498C16134645FF48590CD4B05F6D3C416AB95F1EA5005755D57DD8FBABFE2E20C731E29B2839", - "hmac_key": "5E4F9CE97D3DE51E2E0D9C20C2EB528286B259C12C311BCD67995075EA5230FA", - "adv_salt": "51A3", - "plaintext": "91FA8DF0FAB24EF8A69CD3DAB86C5833", - "ciphertext": "A960D8AF967257CB67C20C5BCD6604D6", - "metadata_key_hmac": "E76660ACB28395EA5E88DD38D585C7C1EEC29D107F3B5F6C5A8980FF63EBB7B6" - }, - { - "key_seed": "7D8E85630617FA51F2A6620B7B3D6C82CA9CC9685DD1D0A29E659A3397D871EE", - "ldt_key": "744289C1913C05990FBA3D066A88BE2BBAF45241AC470A57A37E2077058B048CD9183C89D61CE8E4CCE409825760A121C65B9D2F5A9368E2A88D53340B0944C5", - "hmac_key": "A54E10CEF8ED1EE553113F7580767CD833CBF02A705A92DAF322D696B2B91F25", - "adv_salt": "AF3F", - "plaintext": "6FD2A80E81A51DBDB404188DE0D92FD57AAC5B", - "ciphertext": "0ACC3BB8B7735307713ED4A17BE8B78CFCB729", - "metadata_key_hmac": "A159B44F3DDBE83987AF66D786D8418C7FA0AD036F4150FBFA2581AF26540400" - }, - { - "key_seed": "9EDC5C552240AE0B1DBE3546A9977AE1A78419E88F0E2ADCE71588A9AB771D15", - "ldt_key": "E15CB36AE550637055BDF0B0C1AC3D090F930531BBE11561C3EB79D291EA8DC77011933C945C3931DBC6C06F63DCC14856CEE2456CE836B97D939E83623A8859", - "hmac_key": "96A7C51657FEBB26B5C222633509B49BD0CE08657AE6F1D22462722C02FF6800", - "adv_salt": "07D4", - "plaintext": "4C7EED55AC91676F1345CB2ECAF18CE2EF16FA26378C63E6AAF973EAF055", - "ciphertext": "E964835FE749A6EC67CDD7C8CE659DE998AC244999D0BFB9E1101D222FE0", - "metadata_key_hmac": "BB41BD052705D128D72974CA087A286AA4D71823912477821215CBB7E344E39C" - }, - { - "key_seed": "2F0A7502AAB91AE51E454AFF3C9BDD456038C067927AF5A1F59A42B8AFBE1324", - "ldt_key": "27F7A0F3E9BEC8576855279F97F447F14277670426B033D098FC177690F4027D532B4194E21804D6F6BAFD08DEFBAD8E33F981BB9848E3A18BB8B8D30A143106", - "hmac_key": "5C54CED6C94657A9FF1B83F28CB18A42C3A7F64FBD8152F32FE3EBB3B5F7E982", - "adv_salt": "83C0", - "plaintext": "002F8117AC623541B57404FDC17FBE7A7A", - "ciphertext": "5D463DF93F8ACB5A855AD559A4A64709F1", - "metadata_key_hmac": "BFDF51FEAD1958FEAB8F9804AE00DF89CFE09F404E0A33DD3715E966B0FF8122" - }, - { - "key_seed": "E9D8098A1D31694FDE114CF400F7764AD8C0FF66C489CE968DC9B7F85BCB6F29", - "ldt_key": "1A795BB7754A1A31A996EC6030233FB84B4181BA661B57AE7B260C319E5EF336F221481412F840B7AFF5465D21EA64123232826F14F826F10ABA4B6AA44D0ADC", - "hmac_key": "0BA616BF14EB74E612C6FCE4FBD88F73E95979D4A44C9FBD25ACE1C4E0868161", - "adv_salt": "6092", - "plaintext": "1A9CF3075EA6BDF46397A57F0A41A95B860D171CCE953DC8B164", - "ciphertext": "839AC0809777EEAE830F82C8A1AF249362A88A8AE04EB602A682", - "metadata_key_hmac": "BD3DEC90EEA8EEA938D7B70F3E4CB03985DBB8A4FC429820E7D04AE44355F3EF" - }, - { - "key_seed": "DD22C884AA53111113EB1871AA76F4AB1E123AF3DA235AF41E26C2761247035F", - "ldt_key": "119CFCE6CA9EC347F888D48DA820672E76E950EF1139DE4E1BDEC1B16F5FE07CF7A1CDC71AAC4924A2A261424559D8726D9AB07056E1561F76C36CFA06B2B503", - "hmac_key": "EB93CE75F37A29618B11E4BDA7840627AF0AB75A9E506B248881A5E5E3CEDBBC", - "adv_salt": "E99D", - "plaintext": "A566BBECAF6B53D98F48E3768E3C4FCD17FA02AB734ACA89CC55E8", - "ciphertext": "56AF055A77CEC1CCD64731453E9F51A3A240CBF7956C8D6EA4A7EA", - "metadata_key_hmac": "785124888A2E5C6C91F1168F85ED5C8948709203D55913992DE0753BD5A2C424" - }, - { - "key_seed": "72027EE164E7FFE5B33C93DBA101C199FF334A23BB8D5FF08CA90246193C3BC7", - "ldt_key": "1391D93AE442808B2C6959B795E4758E1110A2AD154339B7519D48756E95FF6B9CA7FA77E3A14262D7C6972752C24EDA69349B67350EF8C8290E4FCD4162BAF3", - "hmac_key": "8BF72986ECCC3C76AE633DEE05E1216F1BFAF4DF9AB01B251F83DF6AE8D23EC1", - "adv_salt": "36E8", - "plaintext": "2E6C1172AE990F9ABBC99E8D6AA4FA026081AE7B3777C8", - "ciphertext": "DAF3A5C9929D8528CC0FB806AB8FF3FC12FC5325068AF7", - "metadata_key_hmac": "058AAC41C80C05F1EA135B0DDFE1C045B63D2B374546BB4727AD58F7D5384209" - }, - { - "key_seed": "08370BB7E2746114C0D804852CD16233CEBE79649CD0894BFBD90DD8B2466687", - "ldt_key": "A71C6B8922C28557DCF3745959FC18304B114429210AA9D1D35F447A7B7441952D051D139C0A56A3E238C8F28165C1AD54D5923652B105FE1EBC96DBC0D9A58E", - "hmac_key": "2BEBBB42C76CA69E1E113CAA7F8C3F69480E37EDADA82906CF262011F246CA41", - "adv_salt": "3265", - "plaintext": "2C3AA9912DFC6FCD751F022456E01D93107F3C5D4C", - "ciphertext": "7602E0B3F97FFA39D8B3D65D2728AA181404CAC20B", - "metadata_key_hmac": "6833E4FE6D719ABABDB8B174B6B3555F85398AB47707B213A8AABCE2416A0401" - }, - { - "key_seed": "F5444EC6BA43146942B5F030F68C17C2FADA2E254301F17D4E5D49D89AB3BC48", - "ldt_key": "3EDE8097F486AAC75C15A0EF41ACBE4B03BFEAD57A0A4672886BF2A4BA34E9A969FC36060833741A9BD789C39356ED413885EACDF6A0428362BCF7DB7813628C", - "hmac_key": "22563337EAB8375B41EF2C7CC64BF7601EB3078AE2D9D9571BBA4141187F825C", - "adv_salt": "F10E", - "plaintext": "18B2C0DEDF90B749FD5CE7CB01F3722565", - "ciphertext": "3E753C44334CF07794D7873A0CE293A415", - "metadata_key_hmac": "83ED296180057DD15A77268FCA4DA0D37EADAE91131E16605827337B96318A66" - }, - { - "key_seed": "B943C8D6155B53C203E332355CB329D31E28EBDA8C6718EE6280D366E89FE592", - "ldt_key": "AA9A6DF6D3FB6739804D6A34DE6B5155E9FDEE5045328CB9288D8F6CC0D1FDAFAD6C778EF2A5DC054046BFACBDC5B7A135AD89FEF0AD7466AB509F8CFED6FFD3", - "hmac_key": "DFD05D449A45276E5338E23059A4234B73DDA785BBC6CF7C2878FDD22936E7E0", - "adv_salt": "1C2B", - "plaintext": "ACAC175BF4ACBEA53E878C9830040AF5122FE5686F2F840DAC45", - "ciphertext": "B180141F52F59E2F8A3584395AF96F189A3538BC429890A9844B", - "metadata_key_hmac": "425DD0A91CF7BBFEF03FF25908BC83967D978B4A4062FBF9732767986D6DAD85" - }, - { - "key_seed": "8CE06788376B0F29A61254B3947C09B169D6A3DB105B1ED640A6876B6B5CB18E", - "ldt_key": "17B8CBD01F10EDCBAA9D94B82487142FF22899A3B09C76189737DB0A31CC8778FCDE98EBC90512A9998A8C113B01C270EE46C9A19221413F844E0068169A7C81", - "hmac_key": "A09521F10A21C680D426A4C306A6C6C283B7CFC8B935318AA425C1181B940F66", - "adv_salt": "7AA9", - "plaintext": "BD625EAFA89F56091A5EF8B6A8364735785C2109895CB375469BA3", - "ciphertext": "BC94290458636AC9FC480582C6DEABB5AD4323BC4D10362A74FAC9", - "metadata_key_hmac": "A4F3B70D27ECE46376EFBD49394A464EF561CB3BA46F044D3D2CE55297E19DE2" - }, - { - "key_seed": "0B04668FADF3FA0F73FF6918544470590955FA30D551139990047F1BCE8838CA", - "ldt_key": "DDEE63D033D1EE3EA7F109E65CAF7324F10AA2CF311B085BB59F0F256231175CDBA6D9BC1C0B81DD15549DA5919915716066342FDFAFA2C9B7E3B5F0791D6CCA", - "hmac_key": "048FFA66EDD1C4DB6657273D5FEAECD80492D1D00250F8B0C5DF4B56519FBA75", - "adv_salt": "7266", - "plaintext": "90C3E1BB82CD5737B438C91BDF8B0228EBDF6BEF", - "ciphertext": "988DA579499FE0736D6D5C251E051612080DA671", - "metadata_key_hmac": "92A81B7CD801716C336E9E5FEF64B7EE2B2DFCA4D53575DDD76A3029CA2AC9D0" - }, - { - "key_seed": "49C8C4A431A2E01DE854151D3D337DAB5F9C9D8D8AD3B2C775FF94FC570D27CC", - "ldt_key": "09C2E5E543710567B739C1ED0B4358B0CCEB8FDFBEF3F59B97300DD1B0B4E7F29E4D0C2F1E0A129B21CCC9BD34490B693309C6E1EC6FD8EA67D21D52A07278FA", - "hmac_key": "0E01AEEE004555F1FEFC9CE595D8B63368EA1FAFFA2042E8CBB54256AF666018", - "adv_salt": "1CFC", - "plaintext": "8C5639623074CA6E565855F80E57B78B1B63CE0DF851A0EBCFAA", - "ciphertext": "B4D655F34DE514064A496A3D72DB5E1D9D68B0994BAEAF308445", - "metadata_key_hmac": "D93C61B9DCF9754D406E93FFE8620E5AB31EBD2C1FA736FE60EE8D67DF5C6447" - }, - { - "key_seed": "3BED7222AD9E096EB49C6D0710BF028BF2267F53A9D5724E31F470848A627669", - "ldt_key": "7E7F49AA201451143832E3B868F2C71CC3FA37A92A0D39CB401EF1DD1DEFC1CA4E16E72CE72D04180019EA02847EA4D537DB90C6C8761FC8CDD3F5346D4EF0DD", - "hmac_key": "CE7D36E89FC7F46E1AF8AF08C2D3263B33BE88CD0634F5256635D3083AA3DC9B", - "adv_salt": "F3AD", - "plaintext": "A7189A5E8E1BBB745424823F2388703E75D4DA0B0A52CB4AA26A855F3F93A3", - "ciphertext": "5617A9ABB6BCF3C7D4C2265BDA4FE80376F3FA5830E1664DF53FED228AE275", - "metadata_key_hmac": "14FDB3DB7DE52D2622FAFB810545E7D92540E2F86B6536F926E2AA24DCD2F8C8" - }, - { - "key_seed": "2192A18C6776FAE8AC7D9D9121CE294CD21613A8647B9EA1705A6585C550C398", - "ldt_key": "DEAE697B586F054E174FB6120981945C2B35F8B2A488493E7F6394181B8301D1CDBF14C4063D34DA2B86ACC5D83254029F04DA91BDCC8D7FB513045067106274", - "hmac_key": "53B28F7F5496579FC377DB08740E197A515356E9C39D1334CCD5AEE6B693EE77", - "adv_salt": "AB44", - "plaintext": "8FB87C83B36F8FF88F70001C78117961EEB97F10072C722995770A91FB22BC", - "ciphertext": "7D8AACB23ACFDD7ADA8838956AE109D124E45B1468A1570E2F81D51A18F534", - "metadata_key_hmac": "1224414289B1D981F35D8833DDC9C2AABEB4EB2578B5033A784CC3E7F21FA16F" - }, - { - "key_seed": "690895E0A5EC222CB659058323865FA32C27C64B98FFC1D75E2A1F8D216C7454", - "ldt_key": "AD3A82914B649DF5F4FE58F221F686703BEC6F3417AEF7A6AD0B9939DDF82EB8FD928387FF09BF0AC06A61DA60CB3CF947157A0FF1EB36165C67748229D99F0C", - "hmac_key": "97FA5FF2E8C978FFFAD438E3307C2A3EC8E8F9AF37E2E943562BFF9FFBF9F353", - "adv_salt": "CA89", - "plaintext": "B7C8FF50A1B64418FC8907489B0AFD76C9D6E0E746D6", - "ciphertext": "DF168092CA200F9439B3D2CB65CBFACBF94956805999", - "metadata_key_hmac": "BCDC98AADFD5DDD75B655888ABDD084623BF9AA657553218B02243D0D72A094E" - }, - { - "key_seed": "6EFAFC8A2B67A573D8386B82219B1DB6D1DEC72A684B2AD08F38796790545C7E", - "ldt_key": "02D510206C3677918DCDE9581AE6C979E51BE47ED70E6119A6837197619A5F8251740D6E1FF383710C24032A7AEB21E7D46ABB18E47C74F1BB64CA714D311035", - "hmac_key": "57EA566577E2CE06CF55D79AFA153ACE4B0B39092A89225DDC91760AB92346E8", - "adv_salt": "3858", - "plaintext": "10E157598521A3CCE5CFABE235057C7B569592", - "ciphertext": "4AC6741D891D0E09D9E0DEFB81FF2421B9A9AB", - "metadata_key_hmac": "081CF6AA6FAFD27C0E27CDA06796FB5B160B03575F8B1820EC6B2ACC68ACF57E" - }, - { - "key_seed": "240D21616C0322C8A79E261FB1B06C9EA51ECAD4725C9DF014112B42E5070963", - "ldt_key": "3650F42E5787CFEE207F2B786DCEE041AE1DE12484E81CD09A1BA49DCEAA7B38C797A0B1633794CB9E611471BD78D251FFC2FCA2B2491C73A4695E1CCAD7213E", - "hmac_key": "F7B6BF48015AF668EDCC0A85DA1E33D446E201C15A4F70FD539C30EC7ACFE6A8", - "adv_salt": "1D17", - "plaintext": "CDA7CDECA0C584DF9E2F9864C550460BEC6E1FCF63B168DDC62D", - "ciphertext": "DDD038E31B2C3E1C6DB66DF4F7B03CE7237D744CB3909ECEF225", - "metadata_key_hmac": "8AED7FC5A7A63BB8C91C89A3B6F7D5DFB0AE983D82C3209155E9977C13B03DB5" - }, - { - "key_seed": "60D8D4726733DD96CC9E5FAEEECD4196E56FE78D3B9AEB26F177B089712ACB34", - "ldt_key": "475E701D85BD3F4A1908F7870A4E39B78D16A17C6F05F203CDB8CCE8FAED2D8A22052F9FA6B4231DFB7ABF2DAD7634BDA0F0F8EBB59D2C4067772B89B2B5D443", - "hmac_key": "5F8DF4E0D61820FD18EC2B0434982A3ACC571D8354E2FD6F4404D1AF8AC822BC", - "adv_salt": "41DE", - "plaintext": "3D8CC8FFFBED83787AC49AF00BF84C5490B9683F8161237726", - "ciphertext": "CF8B5DE010250E4E1A80527E158E3826FB48849405EA452D08", - "metadata_key_hmac": "F28EB59F905CF8BFFAB4F23FB0FCDC82B1AB924C8FD7CAD0E6CFB879C62749EA" - }, - { - "key_seed": "0E8C64270A07290A9DC0EFA078AADD96E9D1A43D103B856AA1B8DEA976F8F772", - "ldt_key": "7BA2957697E3150A70FAD3B30DDA9F834155AA7EF40D3903DCA5C886E363276EC5A9A93658A3E664614355680C7D5A79094C2B3E83A1C41DF2D8477FEDE9D69B", - "hmac_key": "3CA4A27153D5191C0DF96409700FB8732AA5DF9DE2167DF8B8712BD29B3800F3", - "adv_salt": "6B0C", - "plaintext": "588EB15D532943DEE637F9DE79C2BF96FA65A60FC5291EBC09128B2C", - "ciphertext": "3D07E71ED78098251B8459EB228DEC462E5E728D86F3582C4F539072", - "metadata_key_hmac": "FAF4E049053E3C4F0EBF797D9A7472F2712540764192AA8F433D4AFB94B22E09" - }, - { - "key_seed": "42F8351A1D69560CD77080D521CA43C5AD2B24D27511B4789805788AE0BCF490", - "ldt_key": "A05B8EAB1E8C8BEBB7A9DCC2D77D10808228D001E04CCFC2632492CF03A2098C17C84F963447E8CE52D0AD502E08FBD110B5D95A119A857F100ED0125630D68B", - "hmac_key": "AC5AF0BC153DBEF528AC24830ACE0B353D2AD747FEB6CD6DFDDA28D9FD73B6D7", - "adv_salt": "978C", - "plaintext": "AC987AC3A3845214668FF091FB092D7C9C6872A8C6", - "ciphertext": "651FEC99084A6219E9527C06A25A5DBD96BBE1D9C1", - "metadata_key_hmac": "40AE7AA8F795E8903D79BF5EC589573EC14EDF944A5979C039E0767278B4B416" - }, - { - "key_seed": "5F516164549CE07A61448BF6EA3B67E76808EB48AE9E23F5B9E613B3BBC45B01", - "ldt_key": "2F4638A5887B8C79A03E9F9A70C8F180521E1C89C296C6C0570BC30F9E209939C925ECA0A27B98BBC3598C0D643F2769B57C19E388FAAB1330D51572E919807E", - "hmac_key": "E83E459818F888B5FFE944CE4F1D1756D2A085FAB3792BB9797D235288CCCABE", - "adv_salt": "EC6C", - "plaintext": "E0A9E1D478B779FBED7E380BDDE984AEB0776CBB94F1C708", - "ciphertext": "EF04BA529DBC8203952A5F2AD743A41B676A0DCFAF6CEA76", - "metadata_key_hmac": "76AE54AA59CFC319AB05D759871CD008336553942FD2A642CDF3F45F8A42B81B" - }, - { - "key_seed": "91F1D07519065501D139BA56F55F6C8CEF8C85233516B0B936E5899CF72EBE71", - "ldt_key": "1A82F91509DF4EE2E741F3F924AA7C62328B93C16065C0B6079881976B9DEF32D41E4CF1F49659D7E1AF844CE256B6CEA3E7D0FAACB9B97E2C6767D2B8E40A6F", - "hmac_key": "238A78E2EE24D904B795861B48AA742BCAA972F243B83B7B2F1158830A793ED2", - "adv_salt": "7C93", - "plaintext": "9C0C8F74EDCBCFB5E649542B4B04AE09", - "ciphertext": "ED697BEC17E787A69B647720206A0032", - "metadata_key_hmac": "8D787A4933A982DAE8C76C0B8F04E4AF6EB045C83B93D0BB56F8A4569C5CFC3A" - }, - { - "key_seed": "7EB08E042F563BAB1B08C337FB5E14F4F0F354250E971BEE538001B0A158701A", - "ldt_key": "57DBE2259A6768BD83482FAE8DBCD1E31AACF13D5022AB6624DE7D9AC4DC998F89BD40B9CBACEC52CA3ED1E32F850DCD7D54DBAA7A5578AAE432ECFE37883168", - "hmac_key": "0F1FDA0693BF6EC9E80520CD9806000E5783EA4E09E53A708703FDF721ABAFB4", - "adv_salt": "46DB", - "plaintext": "581DFF6D784E78297EC25706288487AF", - "ciphertext": "3B911D1850819B6BE678262388279C4A", - "metadata_key_hmac": "97D98399A449715181459285F5392DF0293B06B50E5215B59EC59D0652092FAF" - }, - { - "key_seed": "BAEFCFD20965FCB31EC2F5CFEBE82A1EDFAEE89B05C8E1A311F4CB704AFE12D6", - "ldt_key": "BF8CD1566616D6B4035F0949793763D15757E349A0C94117B36B984D94D222634D3ABD0B1833DDAD4B40B0B2D4DAEA7E74E841E615788FF41EFB4C327E72AD1D", - "hmac_key": "D40E45D2A0469BF466683300C941CE16CB1D87A9F5FCCEF01D2BB820D7E60B81", - "adv_salt": "BE51", - "plaintext": "25F8CD05696A1F6099E6B2DE452268F075", - "ciphertext": "7B10E66E465C2C1A39E3DCC44F0CE7D488", - "metadata_key_hmac": "326475EAC59CE0AD57577BBD956E70B020992BB137E49DDEA8881A9A44171AAF" - }, - { - "key_seed": "F2CA31F350654CDE5B74EE5F935C4A89D0C1A0DAB7EF4C940F45B3470B42AFE9", - "ldt_key": "A1F1F050B609110C19AA8235E15CC371677CB635D33E3C957F6AC1EEBD669055E2AD6589D1E5B866CF82E15CAF7110E68E6383064DE8841CD6B3FFB1F17C6C7C", - "hmac_key": "6415731461E9996D3F9D0D17048C174A063C68B0371E7DC7C6BAB8D82D87595A", - "adv_salt": "A847", - "plaintext": "242FF7536CAB0CB695C3BDCD5AC4E1B362CAF4", - "ciphertext": "BA117E5881029A9B26BD648573DB9B4EC36678", - "metadata_key_hmac": "B86B1FBFC83B0847AC8993FBB4FCB0978D6EF2E18D163A3961D9D2A9B32B2377" - }, - { - "key_seed": "764FD24C13DD413756DCFB503B37E896009615A12AB362ABA3516898D5449E4F", - "ldt_key": "E34DE7A73F91507B51E1E0DD90067D1D32B10359EC5B23FBCC01FF7BA2347C845F2F2FDBD34ED4F5F888A8266FA9324D979089DA3CF79A8DF7EBFF33F8E5E5E3", - "hmac_key": "55A7F81A9A3FB890D9BD10D02353DDB7BC2A9414A924F42B43C23820A38D9DB9", - "adv_salt": "A1B6", - "plaintext": "ACDC0775AEC80CBEE306C5F36F8BEF3F66", - "ciphertext": "CAB049A35D67ADCF8BA23FF998ED67EDA7", - "metadata_key_hmac": "E61FB791788A97BEA07650424CF5C897CB06665D96F8895AC7D3080E352ADC26" - }, - { - "key_seed": "A7ECE890512661E1BCAF21F66F733E7C06A12498DDA70EC36B72C7A202B2883B", - "ldt_key": "D70CD4BA93ACDF5EF1B6E2D20EBCA2598D7D1CF1B22C3122D680C97ACC775BD20A927C4FAD167C8EDCB0F0F995682DBEB0A411321816BC849B71A4A969A4473E", - "hmac_key": "F7F38B6400532458E17684828BF6D9AFAD7A9177B3EEBBA1227DA1933FF0EE15", - "adv_salt": "461E", - "plaintext": "0BC11C317D3FD1948B8783C9C00A7C1E37E7027DEF80AF892CEBB3", - "ciphertext": "5A59E809B78706551C63F32A0BB3686DBE0542D7881DEDB605281E", - "metadata_key_hmac": "9F4877F0F0847E54B9FB0E571B57BE77C86B3916833006A11CB167490589CC83" - }, - { - "key_seed": "5F6A6CF006136009DFADAB2F093FB7F136D765DDF5A2C81162D5A1B0DB978EF4", - "ldt_key": "31461D55765AB8296F890040A8B496EF8A11583CB2A65D985C89B8C07B5692E1D74005C621F2DBDFD9999D27A931E63DDAC0E647DC812AE78AC6211D365CA6AB", - "hmac_key": "6BBB59A6D1741A403106DC173FA2D7138757FF2ACDBA25BE9F9AFE83F3CA29C3", - "adv_salt": "49E5", - "plaintext": "E176DB23CCF2B4276F45C0A032F3EC5CDE", - "ciphertext": "EBDE72956456209FF27F57FCE5539FC655", - "metadata_key_hmac": "97F3DD6FDAFA648CC9372BB4D58F1E5FD763F7A79DAE21725351E577016BB302" - }, - { - "key_seed": "DC42457FCDA6BC6238F94F141544401DBF37CCF75D171E0424B9E5A104C1389D", - "ldt_key": "5F5BE22616E1D10A50C7E50D96E7CDB312AAA3811AF691ABA49290AA4653F95B3D8C95C989BA527C07CED74993025BD2BAE5B963A7AF88B739DBA504F5E0F7C2", - "hmac_key": "C7C972C1800D641CF902DF6D742D85A07B0879EA9F57CEDD461211F408066EC3", - "adv_salt": "5D45", - "plaintext": "9827D36FD0D50EDBBC84430D4E6D459019E52C6B53265FD085FCC03BB5", - "ciphertext": "5DF869641548FE4EDFEA08ACFE87AB3AD0EECA666B14BC3741553C6417", - "metadata_key_hmac": "3CB01C6B898D25C2AB6141B05F165C971DD03D283455417D590EFCB119091824" - }, - { - "key_seed": "6E02B012D2C249B2B3A8A187AFFA634A3D696814165D091294733CD0927CB79B", - "ldt_key": "15C6536795D92A5C8CDF035FB945B095791FD54F2D42E0C10A7A544B58D03E5DC9FFC82E90B925A7FA906E588BCCE1BF022EECBFC8BA5ECB534344448DE2EB2B", - "hmac_key": "34E596C2F8FD02E55267B6CF77FF6C9C4BCD70C4062E164518909773F648FCED", - "adv_salt": "377D", - "plaintext": "DCB1F0DF300EEDAB51F7EB13E7B1A34ADC87", - "ciphertext": "56ED8FFFA1F5B5E8D14FE31151D9B9FBCBA6", - "metadata_key_hmac": "B30E6439D5E73BFB2575201D3783D56D16A55F14E531ACBDDFDF22A8F50ADF68" - }, - { - "key_seed": "6E7FD0556DF2BEE0A5E8248E6BFA09777B09ADC99FA9248AE0A203BD5E72D546", - "ldt_key": "4E13BF3B07D851A2452215C0BA7DC3680A81E75D9740D2ACB7E423EE16499DA8F9AE0A248AAC834870A83DAD8F556BF3E7F7EAA84F3210F7BF88A87B1E2CA4BC", - "hmac_key": "FC9B78FBBC96AC247F87109C8DFBEFDF72FA5DEB5E7EF96ED32C5060E5AF4C18", - "adv_salt": "F269", - "plaintext": "6009A2AC45C0D72067E2590D93D656898999336182A9BCD158D6A7D4469AF3", - "ciphertext": "48B5502ECD3B4FC6D5C55EAB2CD5B7C598B69F8E052C13177468E28823BE96", - "metadata_key_hmac": "2F7A1BFCA065947FF4B5A3727E56AC1673F7FAF45144F8FACBA428E9EBDD2691" - }, - { - "key_seed": "74D951408C8BDF525D1D122600DAF1CF13379E219E8F08719025ECBB4E958823", - "ldt_key": "25ACA926D0CFF03E3E4035ECF250927610D16E65E78FCAAC886E252053C85F3D819CBECCCDBEEF9EA9FC7286B51EBF945FFFC7AC1666BCB0DA6FFFB3052CE3B4", - "hmac_key": "E519D08BDE2252F9E3DB11A175D8E2501F4F2C2744D90D585B35253EEFB7C254", - "adv_salt": "8EA7", - "plaintext": "F429B81E6551A1DFE75B69E5005C3442", - "ciphertext": "DDC34E29EF3EE45AE97EB004A139CE61", - "metadata_key_hmac": "986AED3A4CB8E42128404558252C29659C0ABB2485C0EF58A91944CDE00C6EED" - }, - { - "key_seed": "5015B6F3FCB89171769E165F0E843830DE54F1EC1165A7D263DE307900E90AB0", - "ldt_key": "DB2DCA12614D43E732D4B086967E15C20F673B49BCAC18F49D51889D90B77FC9A0C3CEC3CB1E9F7B0747829FD48B3E7A8FFB5540E02DF4A4F71EF7B70E03BF55", - "hmac_key": "62DE7C9DE3694C01440F1C3556DCAF94342993B529EE67C84DAD118CF09BE050", - "adv_salt": "E58F", - "plaintext": "AEF9ED706F57423ACC0E1F8C1BDF842B5CAB1596198A75BFDCB0C69B0936", - "ciphertext": "371B68A65E93153D072B54294E661A02B5F9F4141C698EA7AFC948F5DDF2", - "metadata_key_hmac": "64D84E07263743E75FB9B7A3E87F1D52E76204C6DB72FDFF4E5F809A66AF6586" - }, - { - "key_seed": "D598D9A12E4F0A8A488856DBA25696EA28947FD029EC2A592561B857D1DED9FA", - "ldt_key": "3E8FB54018EE15E884ACFD49D0240347FC603675F33F8838D105FF54A17B7FA2A5A7F4998AD8BCEC49910B3B0532445E4312A704FE3D84648844A688717E2EDF", - "hmac_key": "2B93A7972EFEBB2E34BB47F1BB10A5B4EA6D31BD2D674203EFB254FD0BF6DC46", - "adv_salt": "D530", - "plaintext": "D28432AA51B8AEA7BC1BC033DDD4BAC4EB9CC293E1B491720E75", - "ciphertext": "7C30ED5B699760EDFF31AB48D13623F248A2DD3CD6A361B5897F", - "metadata_key_hmac": "D41699ED342A9CD6E34CA6330747693D704A68D22FD46CE3C75133C97669121D" - }, - { - "key_seed": "A9ADB74C0E8791A68C9092989F1C6C0DE5D614865FE5C7DE91C16041556E09C7", - "ldt_key": "B9C152B54C4BFF46C2D352D1E071748B4A0F0D6FC22FA9ADA2A88837294D4D6BADD4C8C13F1A52EF55F5181CA2104B9DF6C3A5B26ED4D4BF45905F93E9BCF51F", - "hmac_key": "E6C27FD7B3731A0337A8931652EFF05B95B051EBADF4CCD4276061018F290582", - "adv_salt": "47BC", - "plaintext": "540B9EC366CBA5BE0437722C0ABF1A30E3CBC81DB3729689B6882A6B9D", - "ciphertext": "2BE37903CC20ED58C5ADF967AFFB4AAD095013B527F61DD5BDF89F920B", - "metadata_key_hmac": "DB5D13407A407CF26BF0313C0F11867BE773FF7299291458BADD747F09912DC5" - }, - { - "key_seed": "BEAE67A8AA47199BC2626358AA92356D7473F60A73DC30265DB47A707005498A", - "ldt_key": "D8CBCB1562E9946CB438F42AAFC07FB595EE60793D00FC0681D186A005097C80F95DFA32FFEB82DB16C9FB1BFDB9D5B9BE160FF3738C627D9757AEBE7AF8D91E", - "hmac_key": "0729DB3AB37CD96D1661EB3DD8116CAF20A260823CA388A67B04F471701E3ECE", - "adv_salt": "2950", - "plaintext": "8861EFAF5A608F48DDBC8DE9435CFB36050B912A183F53310496D5EB", - "ciphertext": "043AE474186769BE54CC26C25475F48B09ACC8FD108B95840E20C564", - "metadata_key_hmac": "1557A1A917F983968F88466017507F840F8E388D3913F438D73A02ACA566B48B" - }, - { - "key_seed": "4C20E2F0BD4B9341954EA544D3C1BFF1BC1AED34D9EFF6255E15A33D3DBE670F", - "ldt_key": "2C6E9939B31CF4765BDA652A30EA2CD707D5F72C15BE420D2F63CC0DAB2B00CD6302FE19994394E7B693F19BFF9152901CAAF18D28C4BD1E1951BEE884BB254F", - "hmac_key": "D94029B956FB35034E791AA9FB9766E397A2C57D3C5E83D74E48076DBEBD55B3", - "adv_salt": "2793", - "plaintext": "4D8315DE8F870E78BDFF588C7162616AA8855F", - "ciphertext": "0A861982E4B1ED29DD0A3C779F8A0B8AB5BAB6", - "metadata_key_hmac": "F4B14B89F1BC2D21313F1EA5F5D244C2FD6EAA53081FDC09A0902AD4FA44A2A3" - }, - { - "key_seed": "0428D107F0FEA47B7021417DC1DF0607572FBE3EC7B97D1FD8F3679A926D6C27", - "ldt_key": "22691BD03AFAE4FC52FF1FDEF7C671E60F4644675F27F9DBFB28595BDDD81A8FAE784C70AE2112057AEC12D09F20CBF5198CBD53525E78DF313360C3D49FEB02", - "hmac_key": "0E5384D5D2241FF235CCCFACD5919E8879F70BCB7A900B42FDA0E3F03C86EBF0", - "adv_salt": "FE63", - "plaintext": "4D3D218F5480049B1918C912A10ADDCD3B", - "ciphertext": "587268C07E7CF0FF60A3FDA6B108DAF9E4", - "metadata_key_hmac": "9072E1C59708E079DB8B3789ED79DD90406EC0D9EAEEA56DC75DBC6A13AA9C32" - }, - { - "key_seed": "EE24B4EC86854A85DFF752BD1270C1A920CD205E87FBAFAD14AF978B5F16756E", - "ldt_key": "E427890B5E32F9043D248E8728F3BBE1BF5339409793805BF4344F911E3348039FE966EDEDA82BEE3ADB02C4A9AFF042DD38E4E763A6A2B114460FDE2D5991CE", - "hmac_key": "57C8FA94E9775407CAC93D44CDC7F716B8A959C9AA3C6FF88299B516E2F74B75", - "adv_salt": "CD71", - "plaintext": "84066CE197807B83FE2B2D2892E4098A0425AEE5F4FC90AF4A94D358AB8CD5", - "ciphertext": "4A6BE739FA649F638A3A8094EEC4AC50D11A327366D05B5767DD604B787883", - "metadata_key_hmac": "88D3FD6B5D9EC9DB66B3155A1F7B4DE660BCC60853661658E82B549FF9AF2669" - }, - { - "key_seed": "7D21D8BDEE373CA89E39EE7C9DE191DDFFB0992918AACB07EFF882084985BACB", - "ldt_key": "6BB9C764A30CC4988B129DFC2402550791B6CF5099BEC18BAF1B19F36BAFF442BDB96053F7B987C2D882ADB049EF28ADAD7358DA038D85B7417A2F034800E157", - "hmac_key": "3C8443399346EC1094135DFE58EE65658D48A8B93F8DA066F09A435A70D31DF7", - "adv_salt": "CAB6", - "plaintext": "B33DA61D07BAF9B8F5AF7E504297BE12C79C938FA097B31A41297E9165", - "ciphertext": "5703407565A8FFB6EED122A705C9AB9DDAF22541DB24D261F696716B4C", - "metadata_key_hmac": "DACF0D1AFA10BD4A2786DBDCC290FEF7964357D70855DEE46981D32ADFFB2D57" - }, - { - "key_seed": "C123E2FF68ECEEAC94D594907CE6974A36F4CC631A0BE0CEE93BAA6C15FBFFCB", - "ldt_key": "316F01C153E839FDF26FA0D74C10A13D18E8DD7581A58C4567211F823E8911EC7AB560E67A504C5C48EA79D9AD4662F32EF10EA2ABD72C09507A3DF0F3E4EA8F", - "hmac_key": "5490A44983A6CCFA1DE2C76DB797E37E60A09AD702E7F86A77340E3F5987C5DB", - "adv_salt": "9023", - "plaintext": "9B3E8B549CDBB75AD0A6F090979C6E24AD", - "ciphertext": "975D0BBB41386C42FEAE347B54242D7FED", - "metadata_key_hmac": "1EC47F888CFEECE4E291E2D3FC3B6F87E2C11DE9DA47199788E0014392E79B72" - }, - { - "key_seed": "2B2C67B7D89E349E24C4F5E1AFD45FF95A1B2A7B830E595BC20C1A46068BD07B", - "ldt_key": "A883A57B567D2E962423204782D9EFC1DB4641E5293FC479E81417CC4EFFE4FA0F87C3491967C895D516E3B66EFDFAAF4F26F918ABD4FEC56EF3E62E0CD3ECD3", - "hmac_key": "D39A023C47FA40C496B4EBF2C1219561ED71C66908457A5997C775BB1E02FF29", - "adv_salt": "0F89", - "plaintext": "00F4A71C855F57F6EFAC2E7ED25214BCB1C15284", - "ciphertext": "6BBE11EBA309FC866465D350F25272BF0EC444EC", - "metadata_key_hmac": "228AEF9DF006B5BFEC0A9FFE3625F6B235825BB6EA05A507967A29B942AB3ADD" - }, - { - "key_seed": "91E81AB6F70CF4121D6FE686CDE42376D55F2F174C3DEA72A2946183EAD3B5E5", - "ldt_key": "37B5CDE4F6F72C3F218377D2EB79D0F0E294FA1CADFA8F3A8F172D54EE8D88109466726D1CE45BB6841A289C32E425531D6F924198995AE792EF588C42058C9D", - "hmac_key": "C3C4D8918CDB5F9EE2B35467EB69E13209C688EEC0BF63DFD899ADF6DAB03B1D", - "adv_salt": "D1C5", - "plaintext": "7B1365B8BEDE25B035574DCA9808295253254E37D6AAE8DBA1C4A581", - "ciphertext": "5FCD025698AFA623C607C407E82A5C98A2B64C79D43013C774FF1423", - "metadata_key_hmac": "25ABDF4C2383532C25A1AC8E806E05EDBBAA6FE842C56FC7F88D2CE75EC8A6E1" - }, - { - "key_seed": "EE6A34E568DFBF3A5A9B32D70D94B9EE942ADDA00686772B82917093A86C5289", - "ldt_key": "41DC0598E99AE88D2A79CA87260734BA5E57DA6C90348EC54519574C9ECF23333B930D3EEA7F7FA9DF2587BA1A06BFC2DF380FC36B7A4342F8AFA6BB124B4D97", - "hmac_key": "CD4642B18BE5FECC7B1D921D47F2D554C55B5370A0D78623C432AA8A1048CE75", - "adv_salt": "96CC", - "plaintext": "5464BE51555FE377829DDD56FDED674C593F39E98469899AAB9700BCEC", - "ciphertext": "0E9802D69238507017A128C0F62CA5296C5503B9D7F733179C4DEED7C4", - "metadata_key_hmac": "6166BD27C01EC510EB4980665D1EBDA18B19681449E737D01E638A948CFF1F8B" - }, - { - "key_seed": "A1C4F866463ABEAE3B89695876BB45C99D23E3ACB1D068F87D8DB31F341D895D", - "ldt_key": "0A33418E578DDDB639E805FC13C86B0C705E228D51826FC24B9FF4BBEBA22C1EA83FF06ADF09A447689DA0047BCEC8314831BE2101C3DA1CE73E0AE02F202720", - "hmac_key": "E5DF138BC655A647097FCDFFFE015F537541B9445CC940E4D641A45514F3DB82", - "adv_salt": "888A", - "plaintext": "5FCCE80B66016827725911C5ABE47A390BF69D", - "ciphertext": "5415633EDAC291005852AF1CA6583A95906F34", - "metadata_key_hmac": "7BB6CD4201900FB4F391F6480ED3AA2A78A25DFA7BA8A16689CA340C07CD305F" - }, - { - "key_seed": "D8A4255015CF363A556B381DA4790049C061ED7C11149F0AEE1E9141CE03AC6A", - "ldt_key": "B1190DDA0098411D337011AEC09267B11E68405370DD91D351F6BE67C824363320D2DD23A0B590CD20039A730A0BD6F8FA90175DFDF1A5A98603832F4B5181F5", - "hmac_key": "6D1B62F94A91438C33F3273F207C59E0AB08ED0EACEC4F1418926866B5C861BE", - "adv_salt": "BEB6", - "plaintext": "9CFE0C86BB50E90886500A72FAEA88323B26E7386BB4", - "ciphertext": "18777B2C7370AC03333F5A05B9DBB83C0137B9077347", - "metadata_key_hmac": "F26F84D886B914A646923108D1A392EDDA0EE1BCB56D5E899768C3B2A335A435" - }, - { - "key_seed": "75578C951F23AE6C3CCF311D68DD3C524D65644CF9A82C6398ADB4727F5ED46B", - "ldt_key": "20C0116F5AEAC61C6C4E3CA4B7700EB756DA622AF5F4DA51D1D65ACDF9370A0476182DC58348701B99A2DF4A0E9E07EF74DC19C689DC147D11ECA05F8B0E34B1", - "hmac_key": "69619FBABE43F9E9CFE6B64D9564672B729671046F5A78769B29464A64F111BA", - "adv_salt": "C570", - "plaintext": "1488352BC697DA5C71582EAA21B20BC9998C31", - "ciphertext": "84B518932415BF7E07C2A2460B2F36446F6FEF", - "metadata_key_hmac": "9352A755CD0A8064C976391DAEE7EC78527040090E87B32F17B3745311C36257" - }, - { - "key_seed": "83E1A954689B3BD8AFBF0AEC3EE3EC1B657BF743FE76413874035C7995F2F960", - "ldt_key": "FD0DCACD090CE274BDECE08B0BAD561A49208E0B3F3032470DF8626933FCB130C4E852DCB4AEAF52B1CA2DF3A0069600BF002CC3EF68A26046A10AD2CFBBA3E4", - "hmac_key": "CE59C98C8B3AB7AFAC5257375102F2305D8B4F00EFB3E7D40E7623923141E78D", - "adv_salt": "6D48", - "plaintext": "F97B454F80F09422EE81B8FE503A326EA5E54AF6A462049B3D8AEDA0", - "ciphertext": "4F10B0C217DB9F00CC5F0691244AC05AAD9F08475BFC91A06C6E5A0D", - "metadata_key_hmac": "21CA22611549B11E465BCA95A74DAEE7B93DD317498D51594C7D3D9DD45D8289" - }, - { - "key_seed": "05F9E0BF2EBE1CB1E20EDA23E96A63F4BE0D5B75C011C4C8282D927B598C5263", - "ldt_key": "F7BA220C37CE316DFED9C7EFC4FBD2FBCC492B0270FB6CFBC1BA52B8232BA30DCA53DFB98A66D0E4FDDF1125BBA5D5C16403BCE3F1A48C2C76C3088ACAA3DD5E", - "hmac_key": "F221E83C2C2EC96672FCB4F15D9012D6584FD3AADC3D4B8401AD18FB058340CD", - "adv_salt": "3151", - "plaintext": "1A1B88D288B24E30B539BC482CE7FBCB087989FA263BB67C", - "ciphertext": "9EB0EFC18F8160CA53E3C2F6969709CDF95FC41BB0EF1053", - "metadata_key_hmac": "1B7C7D810EB0F2812FC676E0D26A6968E0532F11CDA74674207C3E33DD08C4C6" - }, - { - "key_seed": "B06D3B5E08517380C5D05E74D6C2CF9064E1330367FE57E32069471297EED707", - "ldt_key": "6B6D3EAF8576B12C7E48499F0D8F771425A2270FF97517FA515B83A546264CFD48DC0D87C860606EAA033E2FEA773822486C18954EE6EF850DBE20332C1A4AAF", - "hmac_key": "1EE07B7EBF0D85AE3CA14AD3D9050B399A33E8F692915FA6F7C420D5A3664E0D", - "adv_salt": "83C7", - "plaintext": "55A8E4FD6C23ADF7E289A49B71A654DD8BA050C922D89CB4D2A3EC1A07", - "ciphertext": "5C4539AE4FEBA4D4FD85946B6CBA331573EA19AF2828E61F2291CBC39A", - "metadata_key_hmac": "11179074A88D201DE936BE9ABB924AFCD791F7DB800FB9251A4448EFA4BEA4CD" - }, - { - "key_seed": "C9398C533D870FEA8A29F98EB8996D2BA92AAAFB077106232365AA5E4EF0646B", - "ldt_key": "16FA6B9971E2EBDAB2E8BB92A081986E010C7F386D6DFE60AA7F220EE795F87F59AF06FC0CB5D5B7EA75B8A37C2C5FE993B17395D08870011A2FAEE733978F2E", - "hmac_key": "C2282F638AEBDA6B6CB83AE8B1489BA2C3B20552F9123D459A348E4F943E2A0F", - "adv_salt": "33B8", - "plaintext": "B56E6E43F2D788B6F217F1663AB8514EE70EFEC7AD869AC5261E5682FCD9", - "ciphertext": "35D05E1A88A98DA68A2676681A3495A6979E6944B8AD988263CEAFD2B618", - "metadata_key_hmac": "B6F26E91255AEC398D66FB7EE1DAB398654E543A78A719A44BCBAADA7770A96C" - }, - { - "key_seed": "1A999861541652049627B5DCD0E2236AC38C4B2CA22290F43F8D998B2E9B4549", - "ldt_key": "A8A813AD61E173CBD1724174BE86F41F7359560C27BA4FE3DDB99FAC7D8F9B135D7D6346D15725767B1E90ADC11F0801925728298F8850A3DEB6CC05EE0CE337", - "hmac_key": "3486787AE01E544A40F361473BDD8A0DE037E4EE38C2F0F1EEBE2878020342E7", - "adv_salt": "C8A9", - "plaintext": "0728727CB69CE3B4D08D099D34D6B32E398FBCA49FA8AE", - "ciphertext": "6B8108D9BFA4C1FB7F8C2FF38DE3301B45C35BFD2BE5A0", - "metadata_key_hmac": "A9E4AD26DEE22F766BC1966A4C493F22BD3CCE921E460A70ED08A4582AB9534C" - }, - { - "key_seed": "F005F6CDEA5C4CD79FA5CCADF94BB2232E42B65EA39F5A9081922E549B6C0415", - "ldt_key": "0628D0A94B9FEA0AB7E70961E597753B5C9F957933D48AE4ECAAAFABCA46636C30AF9D3C5E193DAB854C1FF98FD63FA440CC5FA4E7343E88385C1BB2D928506E", - "hmac_key": "2F9B3BEA74B33186D4423FA662131C8D3621C0018B9797629D176F9E58023190", - "adv_salt": "CBAB", - "plaintext": "84AC4A1F18981A7FC7280E72841618C5C801899E", - "ciphertext": "B8625071F50C5B735F2CBCE1732C01FA68FCE684", - "metadata_key_hmac": "C2D54C7E0890506A757511E66E9B49FC0839A35EFABF430A3B793AFF68D0CF2C" - }, - { - "key_seed": "8F6FD538EEFBFFF826070841DF3B7A574C085F294AD59AEC77A3D761220F1347", - "ldt_key": "CB48028D27A83F82AC955EB015C2427F250265160FE720F498113A0356DF38078D11BF84866995185F8C89A6AB2347BCE54D56538DD3B58DD72B4D4C1DBFB109", - "hmac_key": "95D248567D50E175A6DB7300C0BDE8DCC9B58833DDBA791F458E8656249F9344", - "adv_salt": "7D9D", - "plaintext": "E5B8D20B29C2B14898568EE81763EE2D7733A6FBAF95C0A3FB345816070259", - "ciphertext": "4ECBD65B155B3B8066FA968CCE9FE28499EADF27DC7A9B8A2B0F072A10B704", - "metadata_key_hmac": "9420F0E1AA0390F1478EE5AD093CECDC77A545EB0A3CD32CF9681525000F5E3B" - }, - { - "key_seed": "777E054E4E9D47B655E8360B43F29604614558622F0BD3C9E2D45B0A7D9D9B61", - "ldt_key": "9A93510F97B92E02C654232F2D22EE5A460EAE5115B27B1196016731B0E1F3F0388226805CFFC8EE744856412F866F7E9C090BDE960DD100F489B978CF3C50F5", - "hmac_key": "15E2921C229F0F91BDE0A0C87C1965EBB631D1E8E39898DCDBE8532ACB5365E9", - "adv_salt": "4791", - "plaintext": "EE7A2F25F8E682EB2A9AE573D680F3935A40F3F5F0C09849", - "ciphertext": "D48581F2B7F2D96D8223A947E92EE90AD058663CDA950BDB", - "metadata_key_hmac": "952CC226F4A9893D59C4E306CC8BA738D8AB37703FAA4422982CB656D1CDCA61" - }, - { - "key_seed": "60837595D85FB629D9C94564C683F91170D9F1120A126BE9BEF9FD198E712E81", - "ldt_key": "9A53A09457D566A1AB52E1B73F7F005C3AD82D8C9B671742C6658C97E794C84F2E84ECB034EDD080C36B5051FFA8B948D25291001E5AF5512EAD90FB54AB1555", - "hmac_key": "5EDED01DADA1BBC98C7596D5D299C2D1C902C8B63831DCF4E7668BD7B8AE02E2", - "adv_salt": "D105", - "plaintext": "46832328CC47013E8EF24208CB027B2031FDF89A1A1A", - "ciphertext": "FCFA6EB4D3625B7FFA881388C17F6A6750DF527C4C9E", - "metadata_key_hmac": "DB6F8E7099F77322B98AA90D085F2CD1229AFD4B5F9592D3C69F93E4FA6B0379" - }, - { - "key_seed": "F24BD20F93B9F0CDC351E890DEC97565B469517C96DDF73AE3120EB1BF34844F", - "ldt_key": "66F36CB0686BC1972703A65C16A3BB8DE8E964DFB7E22B2B5C871BDCE870E46BECD135B1867687BB3865148ACF8D4EA4F8217941C21C657E1B51825332AE3B3A", - "hmac_key": "8B073262374BC7FEC473CA681B3AD64C3AE244168806F8B3333D7B055BB63993", - "adv_salt": "36D5", - "plaintext": "13AD32D79E13E89FE6068C2639D0A979DFC817ABF5EB65218B", - "ciphertext": "EE6A0C64E67A56416ECED8212D26A8973D9B7A96749E470F77", - "metadata_key_hmac": "FD13068038BC515477E7E3D01AB86CB3E93884A4AA04DAA4771AA702A38869B0" - }, - { - "key_seed": "74F59D94AF08B4B8AB90E8D5BC160F5DF494E3BD34238383D0BD18703CE07F80", - "ldt_key": "E5A98C82CDE85C7AF8BED6D7D95AE2968A182AD81A06834ED3AD6FF8849CC2FBE296C6610018D7DC7040CA1B553A10D00F730A6419E26BE425F4EA060436F290", - "hmac_key": "ED1FFA052E38A9A0366531AB6E25E6102B67362B295C124A308AD3D0E98B1C94", - "adv_salt": "7CDC", - "plaintext": "EDC98AFCD4EE6C877AD7066092E9F605FD37D5", - "ciphertext": "1756BA7EB250C8B22473B5F417FF130059B965", - "metadata_key_hmac": "BE98F9AEEA113198E2BAA617F5A3EAA65B96434B4C3B6C7B22270F08D03BA565" - }, - { - "key_seed": "50A876AAA9F8292147A039FC3E5AAC00D796DEEA9690EEB7A1F866056B272041", - "ldt_key": "9664B36700A5B5B0A04D6C3DB8E13E283793CF0616C5ABE0C26B87BD88DD6399959F7A76621CC66A9DB42868489C22EAFAEC1C739FA279CCEC7167DF9936C2A7", - "hmac_key": "8219103E7D149FF294B8DC21413AB8A711565C32F10EEFD2BBFF5FA39DBB026B", - "adv_salt": "F185", - "plaintext": "3B01D21EE1335C2961FCA707B9CB8AB6EAE05C9F1BE9DC3E65EFA67D6623", - "ciphertext": "7BF18402B2AD55BD4375E3241FDC995EBF8BCDE50EB9AB53ABDEEA883A5A", - "metadata_key_hmac": "C225A9BEE2A7A1C387D6E531685A93A3E63DE2AC0FFED415FD20AF973D6A2021" - }, - { - "key_seed": "7D0093DF47228EB2691A090BFEBCFCC8F9E0B3E43FDE8BFDA95401F77EECEB8A", - "ldt_key": "8C59879B57A3DB8FC0B8FFDC4A16FF67F86C4A9F3F9E9183070E063B6CAD120AC97DA26B458391B2D25FE65625578ADCC26552B03247E7502986E10FBE347A9D", - "hmac_key": "6C66B9EC7C0D201CEBB547E46E641237FD3E7398D7D48B751D981C100C700B26", - "adv_salt": "B84A", - "plaintext": "669D7A54C2F14B36FB548C832A4A059551D4AF17FB591A68", - "ciphertext": "11089171A34F04BF56AA50D68C05BBF6C8363D6713E26920", - "metadata_key_hmac": "BDA541B3F1A92DF61CADBFA8E6044F40CF5C4E9B8EA9E2D286CA3785E63D8EC3" - }, - { - "key_seed": "8927B5F048DE267FA27E92F311E6C3BCB1194BF61D84C254928BAD9C0701ECD4", - "ldt_key": "D1784B9250789EA84E380FBCDFD22CC056083D9FF9B7FD5B121A7935D33C01FE9A754024EB157F011AF36F1B9C3BA7910B802EF800052D8B01FB5B6DA0F5E1DA", - "hmac_key": "AA2C9402AE194A0840C2633BCC36B92EF14C18118C5A16FB6F9759FC03F1DFFD", - "adv_salt": "A406", - "plaintext": "76F04514F35F08065D95152315BE28AB78199784", - "ciphertext": "F4EB95F4D9ED24BD4F09377FF8E346E835E71E72", - "metadata_key_hmac": "2A34C9D12BC1C1A3C042AF24C62FFC724A233547B25183A890948DB0ED410E99" - }, - { - "key_seed": "AD74C330596E696ADEAB9A2326F4868D96BDF091E1F627FE9C8DB408302860B8", - "ldt_key": "EFC11D296B8DE9BD0F9938AB79C082F8A1CB70E99BA23868C192AB18BDD7335C38353046E9F9E170CE1864929D7A26E37686D2D730A712E3E1EE01997C8618F4", - "hmac_key": "527C98ED723EB94CB2553F3A5BA140EAF6185EF41BCB277081AC1F5B31346EFA", - "adv_salt": "0F6A", - "plaintext": "139503855EA1C1B7F2CE931658F7C14B", - "ciphertext": "81DB57063A383C64545D8DB9AAAC3269", - "metadata_key_hmac": "A78BCA4C18924966424CD15A2171FE6C8F03CFE528DF26E91DDC8DB7AD23D9B7" - }, - { - "key_seed": "7649A2379FC17BCC384ED99312C1C8D0AC41E5A3EA5A360AE529E8B2261E0D9A", - "ldt_key": "198CC9B6D844AB0A84720CD233C7F00453077CD1433D393D8216F2B9174794FBDF3CA972F46E5F2AF67E9F3F4D2E5CE62A1C90B6E44FCA21FAA116DF1C0813C7", - "hmac_key": "2A2F072409F89924AAD7AFE26786BDB94AE2E2E7800EE70F02D92530316679EF", - "adv_salt": "50D5", - "plaintext": "0745372B0D70EF170B7313CD01EE17DE46C5E051A6", - "ciphertext": "5CC44403295D7076D6AC112FEC1157603489524D32", - "metadata_key_hmac": "D91DD2DD184E0488F50A410775CFBF3ECC71FA1C937080D2639AB85922E72A3E" - }, - { - "key_seed": "53C687E04BFDCF68AE40C325A93403F6015B5018D8760E1087855EEABECD19A3", - "ldt_key": "B062AEEEDFD4B60B92628D7A86FAF9D5D4C4E5D9690767B149EBC67769EA0BA1ED993A6A3FF8EEEBDF6180CC90EFA68D1457EF15AFCD6091F1B16DC1B9CBC84E", - "hmac_key": "02089D1F302A82EDB1D45A2025924FEC0BA8D5BDFD20DE67E7C7447A24A0106F", - "adv_salt": "1B8C", - "plaintext": "F3AA313737A8A88B621E16B5D1B69AFEA0C0EFBBAC97AAFBD9", - "ciphertext": "7EF8464BD3C38BEFB7D7F02B01D9FA021785D5B0E461D74F47", - "metadata_key_hmac": "219AE24B436C915BB07CBEDEC1CFD0576E9EE9ED89F6C07BDB66E0BDACFB1C3A" - }, - { - "key_seed": "5EFE256D37F99059E05CCE98C91D8FADBF0F061E9BD3B376E80447E6C25E4248", - "ldt_key": "0721773F9CD5316A17C039BF9AAE52DF2A9F4AACE58CE86EFD1DE6DAC555C1E787F22470F3E5464B8FCC518BA2D80D83FD966B2BC45EBDBF9868DA5EA6C28AE2", - "hmac_key": "59BBEC4E253D0FA3054C9BCA71EBACFB6EE42C05E0E6C1A1C14C2B0FCC7E2D7D", - "adv_salt": "9536", - "plaintext": "92B2C0A7DDBC3FAF112B39D70150DFFA5AF52E9B4ADBC684ADE2821F32AA", - "ciphertext": "CC47D95B5A23C5FD1F052642291E8D6F33F23B0DC1169122DC1ABBC2CDB5", - "metadata_key_hmac": "F23C783AF1CF6A0A95FB2F5717E09F50304E76E0655E5E6263B84BD1D359AACE" - }, - { - "key_seed": "64590CB65521409A16FA0142F16C2350D4E178C24FA77BEA5D14A7DF4D1D7B10", - "ldt_key": "93FE8120B98DFC948B4E42A883EF866E3BE29557B54E9CF37271731973FFC8FE0601EC6DCD1883E6B7912041545407E047209D319CA4C57BCC466589317649F7", - "hmac_key": "4B28172CD3030B80276ADEDAC85869C4482C5287EC1F01E36A22751991D31BEB", - "adv_salt": "305D", - "plaintext": "F4821701BCF875B3BEF2AE661F71D1A1CC8EA1A6B63E8F9C", - "ciphertext": "D127ABD7C34A2332A4786A1FE59A5D9D210A70F88441FD6B", - "metadata_key_hmac": "50A682324878F91C2116B8887E20DFE9FF9093A1FD53D48D58A2FCB6C4F37558" - }, - { - "key_seed": "7979DFA5770617C48C39D48B1FBD64696A74AB82AC17847B1C13538DA1E6C234", - "ldt_key": "2F494794600809117F931B90A7E7019D6B253CFCCB3E8C0691BF59213C3772F75277CBEE0CD443C7B6B68052A2E3D139AD3E7C728A23452291EFDB348C47D1AC", - "hmac_key": "9DF39A32A8BEDF4E8BFFE09AAF61C0BAF2A1B2446877C5BE70AE79BCFEB089B5", - "adv_salt": "4644", - "plaintext": "9F814D4BBE16AAE87430462F1A7CB2897839196C7C", - "ciphertext": "43A656D2E2ED336A6ADD86DA0F841857E3267F5F0F", - "metadata_key_hmac": "D49688B199580C37CD2D67D62F81EA7C18B41A3815EEA2A2D415CFF03E884F44" - }, - { - "key_seed": "BDD0A68D2B25032DB53FD4015B182F6590F95D92316579AAA2549DBEE309436B", - "ldt_key": "CEC5F5C2D9671A6B65839370E07DC7EC9A069D4F36169A35D1002C869FA70CE2A1DF1DC3B5DC94F9F9C3FAFB37964539CBEEC38B59CC202D2693E21A7D424EC0", - "hmac_key": "0D3A4DAF27CFA08B3E08F8D4977773DD5002D5A3DBF0C73F5EE43439655A69E4", - "adv_salt": "274E", - "plaintext": "5223AFF8A98FE589A49520C98C37E6159D7BF41B73C697D6287E", - "ciphertext": "1E90493938BC297E539DFD4F11B0B4CA17F7517A2A1221289CF0", - "metadata_key_hmac": "04782BC0AF49D03FF62B08E5DC656FF9B764178C2E1AC122E2079C2424FC97BD" - }, - { - "key_seed": "8B3DFE65D57FA3333A13BDB5B91AB5D1F6D18141AD4ACC3A508852DE8C161046", - "ldt_key": "F4BC7BE52635084EB8D416E1A8A56DB127EE7D01B23AE935DB485963141E46D2C08DD0F7D571FBC679C60CFC296AA223DD7D2737F4AB16F974D951D20B32FD6B", - "hmac_key": "AB56C4D61C11D5D44F6AECF314E2C1007ADE2442293F4C0F62B4C66EC80482B2", - "adv_salt": "D03B", - "plaintext": "FCD4F39FB98A19E96556EE968278F96BC143BF4E2AC5EE3A7FF6A4", - "ciphertext": "46D9E7E7A91A891B8A7BEB61FCD19E2BCA61DD807D29286D529ED3", - "metadata_key_hmac": "145148C46BC3E355777C7BCE1694FA6D930ADA73F828C3EAC3D756F1A519C884" - }, - { - "key_seed": "86026B320DDDED39A605D69D60617C6B2FCA91C3C56FF331BF05F6C51ABC431E", - "ldt_key": "999B5C2E8EDD3A1BA956D046A697F47708D45625076FFC1AEBDAEDF7919681A00834BD8A9E5F47BBB13F7317D0D8A27BAB632BA60598074DE6AC132BCB93FBE8", - "hmac_key": "BAFD9A03AB8D977CB058CB99C742EDA9E295ACC9598A08E05AEB9AFE4D83AB74", - "adv_salt": "65F7", - "plaintext": "49562E3817E27EEC4218ECF02737C5591EFC6EBA7E", - "ciphertext": "8AA5E712B6B68F6BD8E43C66AFC092F7F70880F654", - "metadata_key_hmac": "2B602D3DEA760253D2D80924E6A83E7FF48C1C0F31A635EF8B8A8333B1176354" - }, - { - "key_seed": "2680FAD88620C707EF5E04C0B0AED68379F9CFEB108A9FE86E38756F3AE82B14", - "ldt_key": "2305211BA329041A58B9E7F7D96DC136FC0A81CA566480873175F39279EFB0583C2882403B38FB9B7BA1F3DE8C0B500C306D9DCD1AE212D93260A4A2EBE42037", - "hmac_key": "2DB441BC80B1EE16897F77EFAD57BFCEF638B756EE0681E20D865758B0785D23", - "adv_salt": "A53B", - "plaintext": "CA22F3F10ECC21286044F85308DD1A36225EB06F318A62E2", - "ciphertext": "1B7E3D6EC50515D17BEB4D11576F51DAC3F52E84FBC74DBC", - "metadata_key_hmac": "7F3DCA60378438BAFF2D2BF529EFEC3366864382C1022E6530A283B0B964CEED" - }, - { - "key_seed": "DB2AD3D8D94E698A43AFC03F0A81205D6C6DC80D08C05CA80504D2E46FBF0B6A", - "ldt_key": "7F73778DDBCC4E86EBA264E9865ACEFFB4ECAD01BC24CEFEAC2615B6F83D21849E976751818C280C06C446B8725B456DB9B9DD88BF760A12596D438F15BD75EE", - "hmac_key": "C4A64729CA08DFFB6E8A7AB92DF03C295DE7A34762150EEDB033B891A9E12660", - "adv_salt": "DD3A", - "plaintext": "0D9139631372A349ED682389B37E6CD4C753A8ED6C6BE8E8E632092C0C56", - "ciphertext": "BD97B92A8EC5AA9A64EC22786538D1A4D101257AFCDC2FEE94A813C95D09", - "metadata_key_hmac": "47BAC1161AFEAB767F0D9E4C31E65190D7D63B3A652923BC844239B7A65CCA10" - }, - { - "key_seed": "6A8E2419B9C33CB50277295749BC8416BF5BC53734ABFC8C3FB5835DB750C8EE", - "ldt_key": "47E8CB93888664EAC1A75B677B1229ED52F9BD57C9B23A6525D497560D831D5873C1AEF57152F97DF0B11712B037924A4930A989ECC715BB69735B7BBE1040BA", - "hmac_key": "F1200A73068F7F97608065FD0A63A531F12F0D5D6B316A009AA3633FC06BB622", - "adv_salt": "0095", - "plaintext": "BD8463AC015ECC567E98298AAA43B4CF985256F430CE40", - "ciphertext": "F23D667AE8F34C70FD5E1A60F7E76EA32C756910B2DF62", - "metadata_key_hmac": "B8D9EBC74B2410C22236AD72A06276C9873D876575D2A8B166598826E4BC1EF2" - }, - { - "key_seed": "447CA7AC4EC4AD1D34D077FAF0F712F32490A5F175F6686B7CB279B0D1EF6F59", - "ldt_key": "69ADC0054773C67B2DA71B39FE755210EE5902EAFDD5C459AC9F0BBF4C670D104252A2939ABECD63F651BACBD4BA9CD2F7173970522CB9DEAB4CDB55CC77215D", - "hmac_key": "7E2A0336C7D5D1006779D522D840DE08B623F42640F28736DDB6C8D9683213F1", - "adv_salt": "AD8D", - "plaintext": "DA502E834EE6CAE72683CB69EF30635AD24F59851D60242A0C071FC1BC", - "ciphertext": "741DDA4BD7C7169ADF907C71A31908D0A2E7150A2DACE4AB6B820A9BB1", - "metadata_key_hmac": "832E565CAA78115F1CB3EEB0D3F445E58115AA02E973CC0C1DBDFE17B5E84BC0" - }, - { - "key_seed": "8E61ABF357541542C882AE154496B26F9D372B3D10C08EA89337D3EAB5D1E19B", - "ldt_key": "D259C70B97BC97B53A69A2CAA8AE29A14E00D9052B023CFD0FCB51627B23BF41BD73BC345D483D55E3A96986E83702AA9F921B0F13E916FBF916F84AACB49103", - "hmac_key": "3EA948A39CEC88FF2D445DFB5EE0F59FA43213C646072E01752F8582B8616CBC", - "adv_salt": "673A", - "plaintext": "D416E8684BADF6C6E9F8EFACE100CAB859FB", - "ciphertext": "BFCD5685E421AF7ACC2C7F598297620EEDF9", - "metadata_key_hmac": "8E7A56D294210B30A1B4A251A95F92CD752EC9C6CDA3065F5B4A991768F215CC" - }, - { - "key_seed": "449A1D16EA9ADBC4A2AF44A53E2473C99113CFE66DDB93E351B0E14140B83881", - "ldt_key": "40650D278B91D804BE0D9EA4F5D4A89D5CDF9175765A84093F36809B4868B76D08A17645540867143DF93623DCFC38B1741DE2D9176EB1D45DE70F5FC339F869", - "hmac_key": "2A5B0EEE434721352A2E9806DBF5D4EB7A43E5DB3AF54D9A47CB7BFC67BF0330", - "adv_salt": "CFB6", - "plaintext": "8D328EB10CA6160ED71F0EC159931F939826FDD2378C4BD6F974FD78862F", - "ciphertext": "A6B2A8084EE4A30AC6DF3274E5F120F0B978E7DDBD087A71091842E63830", - "metadata_key_hmac": "8FB61E59723D39142DA9C7E143DF2EEE5D759171615AE0B43CF2C3838C660716" - }, - { - "key_seed": "BFE6A29D7441AC00C35E682669C6B2325B4CC367986A6EAF480DDC41E739BCF1", - "ldt_key": "51A8536DA717B0615F8BBB4B9FD283645483432076E404E0CDBEF17F44C695001207F5E90F9BEA9C7620A592B1A3A76BF3A48D50D290A6B8DAE18DD049B52911", - "hmac_key": "74266AED9E569E3B4FE366DBBAECFC87B0433D556483D8781A1DDBD93C383D08", - "adv_salt": "A2D2", - "plaintext": "6C8E5D0796E02C038C6D25A2998C9F9B", - "ciphertext": "A2D8DE0FCED3FEFBDE44D26D9B33C366", - "metadata_key_hmac": "998AE16410607A68B197B084A724D4E8B645EC2DB46F532A3B268B41660A9780" - }, - { - "key_seed": "14675C8D509F1C9BA8F21B20FCC3F3A64ADE514C855A2FE9D40D30F0528C39C4", - "ldt_key": "EC3D89187D94A21BA267BAA8A31D73762A7E5E124DFFE9E9C63AAC620A7E74E6F97099E8C882C6D3FD02ABB30185E70305672C889A5F61B5AC10D4EF3549519B", - "hmac_key": "EBA940DD1649A200EB310340EE57B004F61C2FF41F59456FD103A56FC53B9D7D", - "adv_salt": "D9FE", - "plaintext": "F8A1CE521C4A43DA283B7B9D08F665A9EE31", - "ciphertext": "BB2968F8E2861639629136B31AA471926577", - "metadata_key_hmac": "803B4F21A55CAFEABF53E090F0F79F0A4DB71723214AEED719908B905B26E483" - }, - { - "key_seed": "4BA996FEC8C6A4017A87E3E32DECD8961DDF206C4555E1501216C10C804BA971", - "ldt_key": "F07212C784C6D6FAE257C889BE9BDF9A3B1B35979ABF0F722FF490E95CCCCFE26EB91F6429818D49DF1C67814509A55046D670E379EE3FD26AA11B40F663E017", - "hmac_key": "85BA2AC220066E09866A29B2452078651F28CBDF3068211ABAC84017218D9576", - "adv_salt": "D9D9", - "plaintext": "9D5E90E9B4F45BCD4081E08332788BF804", - "ciphertext": "47B069DEC4E944CBD1F52E8BF5BC20A2AD", - "metadata_key_hmac": "9B8AC2F67DA6B24B163FD82323A71E822B94F9DC0D75D43472FA89AD46DCA753" - }, - { - "key_seed": "55AF213D2853178F29F6C8F7E6CA2EAB13B5C8D2C5FBD156245F9106F34A6FCC", - "ldt_key": "6AC9F5AD053645993FE1FB8BFE62B92F6DE5FA72C5ABEEC3026B8724D0F0E37FAA79C93B9D5D22FE304E3109E32C720483F26706F98E0371391C94AD32010706", - "hmac_key": "48F8258BF98C92A3C15AB67FD073A498E5B8F17E7208F57B32A72AA790FF3E45", - "adv_salt": "3E3C", - "plaintext": "01A6023AD07DDB0117B7178994D571B0D39ADAFFEDD6A5", - "ciphertext": "B07EF173F1E9DF3C893705C3842018B4CA49BFA1C3CCE5", - "metadata_key_hmac": "6A26E7663F0260C89F32B1F903AB1B8720C6932F524A8BFFB774390CAC1AE582" - }, - { - "key_seed": "D30DE8937872512C3C1AF385C79CFC51DD692C27EE0D114A980D0639BAAFE585", - "ldt_key": "1DC7203241B5887272ADE390EC10F413EFD566CD676B4BC2A53E6621E1570CF6B401E2A76C0F827FC7E11FC496E8E94362217CBA881538945A0D59FF4EA84AA3", - "hmac_key": "6CB4D5700E6C923D393F7D4A12DB26BB7297405C57FF69DAE7539874A1A6C847", - "adv_salt": "E77A", - "plaintext": "EA8F563093ECFFF7BF3C751ABAF402B3A1B6", - "ciphertext": "5AEC616534C38A32B5746D9C85C388575BF2", - "metadata_key_hmac": "93F9F68320220CE723583C25E1377EFEDC315016882382D55B366B787BEF3EF4" - }, - { - "key_seed": "75D1FF8290AE38CEAA8E14710994CE07BDB6377A77D86A93699127D7D0D5D240", - "ldt_key": "E0CC15D3F2438F44E4ED7F6A775EF97A1274AD1CA4109D31406FFB4B7A59D65A5F928286D2E3884111CA15586C3B803FAB77249AE303DBE136BDBD493382BAA5", - "hmac_key": "39B17C433601AD44119FA3C54825CE4BD4B2723170F4863F67A1E941ED8AFDBB", - "adv_salt": "6611", - "plaintext": "78E14770A3E0C8D21EBB6EC1A0A1335B7E83", - "ciphertext": "1246E5060DE56AFCDA4790B9E13E14669CCE", - "metadata_key_hmac": "2F603AC08134D5E3DF511B94DFB5EA82FC52D2270B814CB280B765E6A389B0B2" - }, - { - "key_seed": "6AC0862C64F27E75C518BEF4573E063617F0A1E1C581ED11111338A16FBC1717", - "ldt_key": "2BD89F7DA6984B44BA013B9BBF8A9A5C5F97FD3C9DAB15A14F5B03305FDDD1807B08752F72AF883B9EBEDD57E93C764581508C768928DBA04A3BCE11354B60BF", - "hmac_key": "63C68D4AA358B9890B34B55DA9D6130DDBC518B2E7760B00148B4DA56FBE6361", - "adv_salt": "3EA1", - "plaintext": "34B32B27597BBA55EE23E7AA8E90712C277D2C4A9B6DBB92E9657C", - "ciphertext": "28302F2D55C4DB0D9F71318D886C094F2F6FF4BB8ED6EFABB1774C", - "metadata_key_hmac": "7454C2E431FDEBDE6A5C1A2BAB3BB7039D87A0DD030995C6664BE378D8A0F2B8" - }, - { - "key_seed": "88FDD77B34197BBDE3CC14C16303251D9181A76536C29991863EAAAAF1F40721", - "ldt_key": "DD7A188B0E94BBE1EC023D8B71F28E9D8544AE02ACEA30FBCDB0303D2AF56754AC5ABD2169915DE2B532A5DAAEE4B13ADC24FBAC31CF05A21102D58B724BCF95", - "hmac_key": "1E12D7838F469C39A3EA9282405349BCB68399F280AF213811E57D52F30AC81D", - "adv_salt": "B482", - "plaintext": "087526DFE3D3334962F8CA4B998009602CC37057CBEF619F8CE914", - "ciphertext": "F5D4509D6078D1CB847095474BE5BA2046D9856E27DC32B671D5B1", - "metadata_key_hmac": "E196214CE72F93298AB49C41BF123B9228302456C8274D9C5606BC5B2FE7BDFB" - }, - { - "key_seed": "9E6C0A2179AE92FC60D643993C9B5542AE2BF20E919CB45925CA78CC35A9D940", - "ldt_key": "965F3E30B055488732FE7ACC205A2746231536C2A388BE05B49BBF0D8E0C6E5FD10D5DE8E61AFB9A8E5E380680494AA521528E394FDF128E95544C2AEC9C9570", - "hmac_key": "52DEFFC49F6D304EC1AE2148A42CF48151FFD84327A992038FC8B30CD62461D2", - "adv_salt": "5C2C", - "plaintext": "7B549EFF6E1B23E801C4A7E86B1D8D6C", - "ciphertext": "397524005B8C859AB7437C03A7969D87", - "metadata_key_hmac": "86C8DB2A741B5F4F4877776894D124180D8843C9F7B11F32981685797A17E105" - }, - { - "key_seed": "01C7B5FEB270C8B5F67F7F798039301E50FEA859DA976BAB451478054F61E60A", - "ldt_key": "98E30FE5DEF052FDB673E2256CB5E5D6D77E9BC4474C347D57DE5064B17A20542C747E624D4526E711694A6FD0C93C6C13A3071B0DFFE5F77809D24D3EF616F8", - "hmac_key": "E246C2771C7B6301421D4C899C112EA5F7A30F44CBBE4BC2F9F051470FD68036", - "adv_salt": "660E", - "plaintext": "4BD3CE67C5F2ADC18ED14B684670638A85D3BE", - "ciphertext": "7AAD2A9F5CBCF1171D18BFFC4EE6401E844FD6", - "metadata_key_hmac": "C67D9C1B24F31DF322487D0189CA4D8315C6A4E2377C4A240987BCF0609EDF72" - }, - { - "key_seed": "F4904DB0CB13270DCD9C13DC6A14B2E3B503D4B9FAD0B1A8C2770B2E05090E9A", - "ldt_key": "97092F492BD2239364727408B91712492483EDA86875A326D298DB66BA205E2117AA6DC9A8FDEEB4473EB8C460BB19CB3111C8BC3E149ABAA06B90C64999D7A7", - "hmac_key": "1F20AC6B6E2FB0471E43E4B1DBD285315E50D4C11A269197AEDB76CC06DCA8FB", - "adv_salt": "CF5E", - "plaintext": "2EC7E99BBB3A704467843FA7664C8E148B6C59F6DCB00CF99CB070315A01C6", - "ciphertext": "BB16B8B67492AA2B227FBC4261F880D2F5598E582E7F304CFD213BB84A6E1C", - "metadata_key_hmac": "773FA4CB401A01F5BB395A1BD6C3124B8B4273F2CFD12C07C7EF3776F6CDC61A" - }, - { - "key_seed": "EF08F824062BEF0A8379885E8A2531D369A7F77FCC52DF981CF45C8975BD803D", - "ldt_key": "2CD67013A053273F3290E94327DB3779F8D72BC0419925AE248EA6DE838A2A9169085166365ED0726F2520920641860207A65C2B1776D36AEDA0FF253B6390BA", - "hmac_key": "4F1673171A760C49728C6D42623D440630617659CEAA51F4406F4200BD0BA554", - "adv_salt": "682B", - "plaintext": "DC728BFFF7D9C28C04C194CE8E655DE5C72A68C709C1EE", - "ciphertext": "9FC226D05CE13D4CDC6675B453124C58CF21CCD8A6686D", - "metadata_key_hmac": "5F0BD38A5FEE13E89C572D3BBCD59D6906A8E2A02529E78160B6B0B665CA745B" - }, - { - "key_seed": "516D4CA6FEF5788DE764D7829AEA6CD87B66F3DC677E440391A39C2C75F5899A", - "ldt_key": "FABE68B1BD045ED62A42A478983D0B5496BE7094AEB10C579FFB72DBE52B432A91A4BFD1CC867B70D8BFE542AAA1F70B1D1890A96742B60C3105D0DCC26DCA9F", - "hmac_key": "84B1A7D838FFCD52EA99FA2CE46540C1A49473DA47D865A4859124040B3DEC3C", - "adv_salt": "62C5", - "plaintext": "5C262484CE732258C7C97EB7CAEF655A5C", - "ciphertext": "5ACCFC002B86B8EC3E23879BFA4A2D6A23", - "metadata_key_hmac": "A600A7048E963214232AAB951D5BD884833B6207433C26B07485591E332EABE4" - }, - { - "key_seed": "758C9C6357A68FCD50EBB014972FD60D66D0C2EA6E30D982AB492DD313A36FAA", - "ldt_key": "C63861C29A721E1464BDB8099AE4429A9E4A6A0AF623A9BD22E2A72BB6EDC52ED634DFDC003C1C03BB39123A52BBDC32430AF54B6D5B5A9BEF490047282864C7", - "hmac_key": "5E3D6B561624A72FE89707F9F95BFA7863737FA85134C14026902D24FEDA442B", - "adv_salt": "D2FB", - "plaintext": "89B5B7B59DC93D5568823BC33E0FFEB5B020", - "ciphertext": "5D75ACC238F0501D30483E07AC68CCB5E4C2", - "metadata_key_hmac": "0CD25D3F2762C2B5CA1E46EED22D39B4C97F08EAA4AF77FB40AB952A4C9421EC" - }, - { - "key_seed": "CF7B614C39F7C9D809D10867B102C69FA1F0BD2EED5E1C26A1D06291839AC194", - "ldt_key": "E4F98D2A202F1396D39B2B5A97CA978E2FC65ABB12302A06287E48975B0CA92BE0F2E0C2E4E978E4D1A1D83F1DE80D588AD3F246BC0D733536B3994700115110", - "hmac_key": "5496B1E574C92348AB6703BA4D70AAEF53466CFBAEC879B972DEEB9E27523EAD", - "adv_salt": "183E", - "plaintext": "298D7EE333860ED9A72CEC1E6EDDFEB923FB6EB48BC484B085895A5DB8B762", - "ciphertext": "B1C3E51BF8A181295157919A52C60DC02B3F4E33F072F7BE486340F88835A7", - "metadata_key_hmac": "3DF8E873299A132D7D0B5A0DB1CFF485CA89ADE72C8A8CD7AA5ECA4BFEC0B992" - }, - { - "key_seed": "A8F3550C8371089061BEE8B8EDC64F09B0F58580343FF879A554882DC9FAE616", - "ldt_key": "342F4120DA408811C9ADC0A7F85C331C30B55A33E7D425ECD104C62E6D52F716DCAFB9F44EE29BC4EC81559682572030EA32A42237F3652F76648AE6E345D53C", - "hmac_key": "DB63910B29395E65D5C5DA1A172F8246BED6B349E22F4B2C963F9A0B09E8EBC8", - "adv_salt": "B16D", - "plaintext": "76F91DFDC368BF8312BDF3AEBE961C817A41DA1930299EF6", - "ciphertext": "8F0CD899DFF12A11843D48288E066F22921D374C38C44B66", - "metadata_key_hmac": "6EDE5622C333A0BC90CC266F7DE76A5F3050D36B59844F78088D916E43EC9D11" - }, - { - "key_seed": "CEC4E08D1497E1273DCD56114CE693B46C5E883C90369C4D544D4BCF43E1AE35", - "ldt_key": "427044439ACC208943B46E74C836E35E370C5FA45C51451FE51A372AB326B2BDEFE92949B6A6B9F23D865AF1CD08688740E430831CCE09F44AAE7A51A1D1B874", - "hmac_key": "BBB2D08F9A8CB36DC8C4D2444080592B79F8B0F243A474E53DB36A17F1E2D757", - "adv_salt": "205F", - "plaintext": "3B66942104FA7299AA5FE643F85B3BC2084203095386E06AF42844AD", - "ciphertext": "063BC36BC6DA593AA7DA9D271293A4FC9BDB23F7A50FBEB55F7635DD", - "metadata_key_hmac": "B1E26FEC1DB4CDB1AF8AF4CE130E6947ACF8627C4BD253D2A90FBC8469321A9E" - }, - { - "key_seed": "A938967874DC769310EF18AF3720212C1A0C317C4BF2B9259C5D0F25A974782C", - "ldt_key": "190AC6E0427292B54E2C8AE522D2FEDE65FE7EE51B1030B282869C243B253856F720713E5F1D695A9FB84F1B3B41B5B03F414C39A744C64EE084AB782A7C8737", - "hmac_key": "FF4309DF5A621410CF29A79D888BB996AA6A1A8DC97317654500D02B959DBC1C", - "adv_salt": "B0DC", - "plaintext": "C653B412457A1E824D35A702341C62A6158B0AF17416DEFD26C45AD4B68685", - "ciphertext": "F904FBA6CCC73F8678BDB66FEF230A1BD939CEE951CF5F0A309C80CB7D20A1", - "metadata_key_hmac": "3E0EC6995B3CC21278583C36EB3131CD286A914372FDFB8BC60AF6A4EB21CCBF" - }, - { - "key_seed": "C4A063F997A8BEE12EF03654D5AB2103701DFBC06178CF024813563D60376D82", - "ldt_key": "75F588B1D0CF0E6EBB36AD844FC64D70C095E1FEFC7A08FF6D6D281D0DEC16A84AF0122FB5F9AF194087E48539394F8F045CD3E73D9BCA8B9D6E81F56B10B40F", - "hmac_key": "7D410DE31312FDD5BD22C27B5AD5406EF865981A55DBFF7CBF9C50814533C8FE", - "adv_salt": "BAB2", - "plaintext": "A9A15C93195D562D93FC862450B2CB51D5713FE1802A352D6A7FDA", - "ciphertext": "32EFACD41EAF68E171FB5B69EA53E8FCC448889069DFF470274EB4", - "metadata_key_hmac": "29FB7A5F82F38F5CDE0BD87C3C0C9F4F5D5C0FB3E94692CD85FFD9DA6D986CDB" - }, - { - "key_seed": "C59CF43DE156A32EF85FB2947202374AAD3A105A173C6B1B50D59498E7BDD500", - "ldt_key": "E82A096577F720A8A992118378C10A3C7F770A7199FB5DCE9D479827F83B6A9B2654DDE018A56466E4DBA5BE06A052282BC05673641B91A37A1543843614B9A4", - "hmac_key": "0B5E15435209FF9070BD66C848518C86E0D2A062ABCA4260ED996B902E8B3F1F", - "adv_salt": "D85D", - "plaintext": "60DC2EC2E103235C23884E45A9C2EF427A2E98D3923B576F0C1BB58A", - "ciphertext": "9C4AA1A4604FB62790576EE6031576C8E9FC619A2F9E0D4349663839", - "metadata_key_hmac": "DC075B77FC337232DC9395A38F3EDDA35A822000B6784231D7CC23511333DB2F" - }, - { - "key_seed": "A4C12AED69924E2223FDB1D8450A0DC6F82783E01521CC0C3C96E112FE000FF4", - "ldt_key": "5C526E81E863FABAB12F1ED6CEC79BC2A79239BA1E2E53270EF9E5C7B5F11C5ECB94DBCA6133DA2901D32481ED0CE15FDD1ADE9856B1889453FAB4DCFC57345B", - "hmac_key": "CD5891750C1D996F42B1D8DF01757164A8CD8811B36EF3057FA99165DB369A81", - "adv_salt": "457F", - "plaintext": "563AD9669BA177ADE51EE76AA74606746E3830300C43FBA4C6127F", - "ciphertext": "9F725A80C60503920F816FE26D86C020AF959DE72819C389A274DB", - "metadata_key_hmac": "F78E71F1EEDA9856D047B6C5B034AA4911121C24DEC49071F3FCCC9D56E7A239" - }, - { - "key_seed": "50EB78011D344239B5A672730375635028EE53B4BCF39F1EBEE2AFA0C7FD4DA7", - "ldt_key": "C9EDCA4D84F83300442259B72C913B2352E974EFEA735984509C7C3C89511140113DAE1D6592422CDDF1380A4CFFBC2EFC547ADD64226F4725250037CA7AEFFB", - "hmac_key": "A7FA7FFF75FB13F7CC735076BC6639EAFAB3B2F7A3876055A5769DA10DBBAFDA", - "adv_salt": "FDF1", - "plaintext": "4C9469FA5E6C3E423D991170E7B115CAE5", - "ciphertext": "54BB9C1AE09F6369A5C02E5EE582A5DEE8", - "metadata_key_hmac": "08A663EED16372DF10CEE203C8472FADC1B3A082ADB5F9EB54D1680389F2A7D2" - }, - { - "key_seed": "27D53BCE7DACBA568A39A1685F1645CD36AC503AA659A83EB0559F7AE9F33C14", - "ldt_key": "3A4FCB00294BE8BC6913C53D92C13E51D9C871165526F32187E555B31022C3BB26A60AB46293C947CED45165A6FD08A7B8113E8783BC7555A5E883F65F5E76DC", - "hmac_key": "66F9A512346EDE252444201B7EEE77E2A2BE2574F97092971DC1C27DA3812E4A", - "adv_salt": "9107", - "plaintext": "2C01BEB9AB5896B9A0FAEBAA5498C5B9A11938379AA709C386", - "ciphertext": "E52A5E350B96CDEC882EF5557A3B35073A01921E8781D24CAF", - "metadata_key_hmac": "4C8DEF8F58FD02CDDDE33615AA6DF31DF5AA06F2C44B6F7AA15512B4ABCE2A07" - }, - { - "key_seed": "6D33CB29D83E251854842D7C5FDEC63D72D40A5CF60535E663350E79DBB3A25C", - "ldt_key": "F713D6D7957387932E6AFB47128E764DD8147CEC7E4222BE94BDF7FCF36AFDDBD735C5FD7841BD965800F6EFB7FA81F3514C58A536864B4864056824AE5FC9D8", - "hmac_key": "8E1668B71BEBA3F0D410DFDBF89E21AF816A5A2D0020D81001A976BE50380401", - "adv_salt": "3E90", - "plaintext": "C61353BD81EC324DFC41C3A1B0388450B94B19DCAABE01515373FDFE3BDF4B", - "ciphertext": "4BF8452123D8077E6548298DDCE40FE81CDBF7CF6E71C42EA41D3E6B8FBCE6", - "metadata_key_hmac": "2A8B59911F0B67E1B2AB133F1DF940CCECEB7D2149CBE6B68B7AB61E9204BFAD" - }, - { - "key_seed": "E95A2C13227685460E6BBC7D00BAE0027F3BB83C89A8D7D9DA75EB2E7BE24C5F", - "ldt_key": "07DCF561EB4F767F9A1706A5F870C734461757EA1E0B053767605FF97152C8014C23BFBFFF875ABAFD43E2900F813F212ECF21768970A768B0DF3530F2473FAF", - "hmac_key": "ADDF6476780C628CBBEECCA568634C08A5B7BE6B8A50A67EE239B6C33E4EE994", - "adv_salt": "693A", - "plaintext": "7C73167198F8892EACDF490274257147BE8DF0E1387E7AC4", - "ciphertext": "D6B8DC7EB1701B7C44ADAEA9CCDFBED04AC6708ABD1A0C23", - "metadata_key_hmac": "440D97504963E18A99CCDC247B74916B80FAF5BC350872BF6365DA6A5334D23D" - }, - { - "key_seed": "7B7F89ED9698576B9E30CB45E8D002EED1AC98346BECB30259100C730C51B289", - "ldt_key": "E858AA16B55C883F9BDC8EB94C25D17792D53D701844319FA1B854439B66FE8B199E5B78BA0B4B205F9D3170F2D6DC82333F8007680AC4F4B8E835C5DEEEE981", - "hmac_key": "997AEE99FD7C55377EE7217B5929F8DD078F68D8B2ADF87FEFF1941954F7BBBF", - "adv_salt": "5D20", - "plaintext": "4C87F23FF747A320E0F23BDFF990DB02E944AE75B2F04EAA4693C7", - "ciphertext": "5CE9CD9CCD7F347BBF6D8058AE3BF6BD9105E0F5018076515A40F8", - "metadata_key_hmac": "605AF3BAFE459C6A3BEBD895692BA73FF7387CA41E8F600862853EAA1C09D92D" - }, - { - "key_seed": "6735B5573164DAE91ED565C002E77FB95A4C1113E9BBA940C3C114FA7D35CFE0", - "ldt_key": "7815EA6D91FE6E2AB65CAE36A3EC31057E7EAF0CC9985D83D582DE9AABAE07B991A4A4E1361C163B016FB779D8E06034CB638F2882691AE6E098F6BE8D493AAF", - "hmac_key": "4E41D32241A202F0C4D4E6E57492BAA3F2BD9BE277707B49790A028FBB83D26F", - "adv_salt": "B94E", - "plaintext": "DC766ACAFC7839796FC4CB092BCEF22D57C2B3B934CB17976776C582", - "ciphertext": "DBD0C3B395801B837F3DA56962386491455E741F9009608E12B67F58", - "metadata_key_hmac": "1BEFEFC89AAB43D2B10C7255F503307616980A873520C758DDCC7D1751E53A0B" - }, - { - "key_seed": "B5C2FAF80689B16BABA1F500BAC5A0D907836B2C2BD48482FB52CAAD13E93B99", - "ldt_key": "0F77697600CAA022B28741FE42D64F32C35FB5DC4E766EBF3CBD75EC0ACA564553C7A134BE4CC8AC1A5D150B6AEC18AE1A86EFAF14EA3F2E837C0940D3118EDB", - "hmac_key": "F2C8D1A0A7A0AA4F5879E1980D30D38D5921B6FA1EAE8D37F589ED6932F0EDA5", - "adv_salt": "93B2", - "plaintext": "FE7D74A15EB5BD5E1766E76DE7BCAE615434", - "ciphertext": "B13912720CA1F0F40F31C6CF76F9DB530F16", - "metadata_key_hmac": "C6F8B4B3D3F3118C444C6905B6717880A34A7A9A15E46B1C94B9C8B2577C82EC" - }, - { - "key_seed": "673E1E6D508B013132C409CDDB225CE851E2A1CEEA62C4241E63D41B85BBB420", - "ldt_key": "FFF7B05202440B7EDEB45E6B04D27C8651EDBBF2AF1F7A1EA28EFBE4059D80DF2AF1E8AFFF0522D0057D543EE9E18019745311C527B8FE9512D3796B7B90B976", - "hmac_key": "073A222A4DB5FE1F62B73C76E023EDA3EC4204AF7677543020998F454C4B30B1", - "adv_salt": "0C07", - "plaintext": "69DA685B42999676CCBE99073CCFED628C0376B125F6B5496B78B788ABD380", - "ciphertext": "E35B1BA68A8A40B8B9A9CBB2F145862506D4FACCECEE38FC37DC4EE0B7420D", - "metadata_key_hmac": "3E22A0BAD2D95A023EBC67CF26FA7774F60F0A9587DDCE0C50DEA930D1221F41" - }, - { - "key_seed": "2A473F648120ACE551296E5F1266964BC978D9CF662CED89DBBE897CF97998D0", - "ldt_key": "F1D9A4C4F389D899357445A9CDDD7AA053309395801A8C85EE1AD3485E7C8D48BEBD36DF5531E8AC18F248744DF36F30DDB5F27109EAE58005587F6A662B5529", - "hmac_key": "0FB6CC7B6DA175842AF6B7C17770F74026EF4DA2369ECA21153456FFCEFBA0DE", - "adv_salt": "81C4", - "plaintext": "2FA0659EC174DB284AC1B07274E862BEFC38", - "ciphertext": "76F551451F9ABFE686DF305375C2522A7F79", - "metadata_key_hmac": "76DF23DFE3A042FED827F288D8BEC0C85DFD48955283864A1CFC80DE1410F314" - }, - { - "key_seed": "0CFD4B3DF60D86C2D5CFB127375A5E709FC9A1D38BA481BFB708832059D07060", - "ldt_key": "DE876355D785107000B445C72437B19F594ED1319482701CA67A5835A2B82096EA1B7E906F511CE8DC115EF8275B3519744B0490F8C60B2FE2D4A91A488B2669", - "hmac_key": "7A7490CACC3C85B6E928E05CB34E3B42BDBAC5F51B2D200E846AA79382A36757", - "adv_salt": "8535", - "plaintext": "F60CA2F3F309D84720DD859265AB8C0BF21B21A7B4", - "ciphertext": "712A8FF93C2B67E2CD5CDF78A77260F58C8C409F5A", - "metadata_key_hmac": "8F0CEB0724D4C9689E9EE0BF071BB8286F14912EB8ABCCFDC666BE235978CB0F" - }, - { - "key_seed": "637E997D7775FCFD647ABC97E5F205395081FFA752CFD8EE44DDBA22DF14C00E", - "ldt_key": "71A3170FE7684E36FD017B8490831E7B5EA24009D6AC494F441D85006C9C7076A47586A6BC43BD5A31E1C70EB9F4BD2F186D935D10345E4F006DC400845DEC79", - "hmac_key": "FE7F91371BB8CEEEA765089944543F3389C44431BF670A2943A6C9657C9CEA85", - "adv_salt": "44B4", - "plaintext": "A1CBAD09790C0302AB3CAB721094A285E7A6", - "ciphertext": "700A33D436DF6CA3D1B1E55CA1011F7255F3", - "metadata_key_hmac": "163E8E307FCEA7394D487D98F76039AF24648CE14200913C4CDA3DC4E3B7DE4A" - }, - { - "key_seed": "454F7C4FDD05C3D7EA764FC8E988E836040D5AA71E9FC008316A56947C20FD9D", - "ldt_key": "071D5BD7EBD02F9FD0A914B726A055EC3174349EA6D84F9DAD2E1968CDC754D2953CF003445804E2528F8A3E17BBACFFBC095B09C4E7ECF361EEBC8FCD03FD88", - "hmac_key": "40258B6551067277782207D800EB3DB47059EDC830FE2A3246C82800AC93E0AA", - "adv_salt": "E880", - "plaintext": "A7C046F982D9FD6B21D3A46924570B90C64494", - "ciphertext": "0301037705FD66CF960A4C81FDCBF5C8F8DC73", - "metadata_key_hmac": "C278DBA0E3C2442469306211A58517E65AD0E823F887736F72ADDDC72E8EC47E" - }, - { - "key_seed": "D093E0138C4A14E63567A46E37BE38A95A933E2B18FFD593BEF05B85E0EA68AD", - "ldt_key": "90948ECD6E3F08F28779605A62AFC7A4E12597C169E77E0DB269DB251A5D2BE6227A49974B79F3CCF14CF8F635ECC3EE79DAFE98AE4305FA3E7BE4A693040208", - "hmac_key": "AEEF514026B55FBD72224A96638493F83808CE90BDFF8499216CFC2D42DBFC57", - "adv_salt": "B1A4", - "plaintext": "858A256357724C43E415C3475B165A34C3AC9D19423B2506C53B", - "ciphertext": "7FE1D27B67DAEC6829AAA383A8804E73E8A7F30C1EF8919ED380", - "metadata_key_hmac": "CCEB348AC6ED5D37DB1820EF0E088213A71D94BC32FF93DC6C7826BC60C61B4A" - }, - { - "key_seed": "80F2AAE12395E3C45FBCCCCD4CE458571AC2D3B5F3C9105298A0DD4AF317D879", - "ldt_key": "2ACC8ABF12B91584285D9217BEC51965647BDC25C38E17AD2ED19E139C656AAC431FD0E469EEAD559CC4A801B3EDF474A207E2FE57D5471F96D37E8662B77014", - "hmac_key": "F46746E3E06EF3A7FAB7005C249AEEBE9539E3F4C264CFA90AB61D956B00D430", - "adv_salt": "5498", - "plaintext": "E50C9E12135D4C7DE7D8F2C2F9A16658D01884", - "ciphertext": "B896FD364CEF99762DB1650370063F805A8840", - "metadata_key_hmac": "BEBA925F567BA2ABCDC3B9F5C92D04A0D7BFF3206448C15623E563B7FCCFF276" - }, - { - "key_seed": "C96E4191747A3C54A5CA948B13CF3684CFE72376C48A944792DFE1CA8D68E49F", - "ldt_key": "85E7CE34452DB08C1092DD77849B13EBE15914A40660C16A91B2B26C21452331594D68F8920900E147A6899B7CFA63779F9D96A8E819C1F6D4611CF3D0EFE974", - "hmac_key": "AFA3822EAC8C7129315950CA2548DB5605F2CA378AD85E0C9151ABFCA816B7A7", - "adv_salt": "03C2", - "plaintext": "596D0202882999D31346C62E5DC1A7AD4F30427473E99A144BE43A", - "ciphertext": "BA8CA0694A4B92C46BCC64954BF0F0B77CFA8D071FDA015F98E39C", - "metadata_key_hmac": "76A8F3B97E05C47118B56C5EA74CE0BCCAAFE05C758B8B60D388DBD425309478" - }, - { - "key_seed": "BA7ECB1E5C504F05039DA4D49A249131E5ECA00048F5B167F7BE7CB0F157C1B7", - "ldt_key": "D7C9D80FB954BF225624BA6A5AAED8EAB9A0DD87E08F2AA6735E4DD820C57A6832E7996FEC6885BCC768878B7180561DF95A1507832C98FA0378141DF7247764", - "hmac_key": "1612AC7D901DFFAA784F653CFE72C860F07D02D9AF3944E575392342EECE8674", - "adv_salt": "7C01", - "plaintext": "2FDC4609B6CE14A81DEBAF4E75410614668FA832", - "ciphertext": "8F726C4754B0A4063F66C3F17403B6F205548AE5", - "metadata_key_hmac": "7124713D3393FC2127DD5807AB32A4FF9387FC413D6F09E6FB384BD93663F125" - }, - { - "key_seed": "6A262CB3E191FC39C51A0E668E86559FF5921C45343023E7453BDFB00FC666CC", - "ldt_key": "DB977C5B5D21458CA2C443EAFFD6166C8747F3365329BE64E1A64B65625E976436F667BF1CAA6C37B8373C2CA668D3F0605C50146610D0C192CCA0B8FBC40255", - "hmac_key": "0747CFB1BFBEFC45F41F2789B0868D6C01660CD37F8006F40AA2004372A05546", - "adv_salt": "3913", - "plaintext": "2D9A7F0A1695C480881FC6E090D39257564551", - "ciphertext": "8FFC40566A06DA6BF601EF2F7D819E3F1C6B8C", - "metadata_key_hmac": "2AFE4B48FB0D88225DEEC8067C47ECB280CC3B82D05CC3A5A200D96112D2BA5D" - }, - { - "key_seed": "76CB008E2E1B57DD9874055C581A63FC92D9E9800FB63A0DB8749448A6814E1A", - "ldt_key": "B5ABFDB94FFAA9933392FD04EC0A79FEB1F12082FB14D45927ED495F33303BAED6FEDC64BAC2FC6DC39E3F96F79B21BF759B6AA8A28BAB7E0C12D0668A796BFA", - "hmac_key": "35DAECA2FD83A07F6081812821327972D968BF5642CE9081BA08B5D30706DAE4", - "adv_salt": "3AC5", - "plaintext": "548886B7B5D63513CAEC671632ED252B0B3D31216A60E7F1840F36EF", - "ciphertext": "BE79E939E021C2F93978A03220E2E106B98C2E1AB7C81F3E8A564BF1", - "metadata_key_hmac": "9EE785528D80D745CB0223E4BFAB2A72FAFF9C6AC999E81DD82567C42A093B4B" - }, - { - "key_seed": "734A5E8CEFCE9DD5EA33A0D218D22B591BCA71DA64279936D33BC06572CAE44A", - "ldt_key": "3C2BE602C84B67E195D251C657B5488C50F6B683E9EFC5B6691148A53C63A2C237A833805EAA9875E8DB1D97A746D22E9933F21FB7D84F8140985280D1D3DF1D", - "hmac_key": "BB98542D66C10FDD4E6FB3A5230D4369B17A48C60BC14D717BD542A8A131DFC1", - "adv_salt": "DD2A", - "plaintext": "AB1C28BD51FCE36F10D09E48261359FADB02B0D8FCC01E53423E25", - "ciphertext": "677A41B92A745B7B6EE2305D6D2DC67A9D68C61B0E1E09AD12DAE7", - "metadata_key_hmac": "C3C99E314D2E8073F2D2E6E77A65FD8CA966D77B3ABF8CA3E6B119A0F5E980C8" - }, - { - "key_seed": "AF06B6C79D84CE617AB5F2B490BF47B9B004B9B22346973BCD28075F827ECF99", - "ldt_key": "3F9FC45F4D363DAE68DC68017CE6A50379969FF80C95043D3F1AD7D164EB3A22EFB0A6BF5B7C5F32F27B8CE48B9C8C74D4751EFF15A5A3F366A83092618707CF", - "hmac_key": "8745D4E53B92E1BE50BDCDFBA6BCCACEA494EB01B9E11D93A5CA20213B1FC24C", - "adv_salt": "6D2F", - "plaintext": "EFACC5C8CEB14C77DF12BCFCDA089B28314458A3763415E50F1736", - "ciphertext": "D46F82F4632B5D5A87A1EF6AE88F1E988121EE919BB0AFEF8F368B", - "metadata_key_hmac": "28CD7B159662B6BCA85C1A88194E807287813E3A865A5DCA755D27DEC02468F8" - }, - { - "key_seed": "4C88A40586DEF1E66FA06B376E94EF9CB0FECE6FF56D7D835CD5CA8633635E3B", - "ldt_key": "B084E839128D948FFDAAC25A10504AE6903899794FA31B17BCD301A5AF9496D8D74D231C07578A81D76FD43E7F133804462BED251DD562C82C8649322DAC37DD", - "hmac_key": "46C76D514FDEE225F7DF352BE4EBECC06EA9B981FDF241D137D77AED1D2EFD18", - "adv_salt": "E728", - "plaintext": "741215B7CEFDAA6BEF56FD3FFF8D12E9758BA4DAAD649630106F673C608153", - "ciphertext": "5315772F06F221277DC651FDEC639507132A13CEB75B181A455945BC3BAABB", - "metadata_key_hmac": "6C508E562A98C11B851A7451D55FD588DAB288EF91A59D74DB3EE7A75B1F7928" - }, - { - "key_seed": "24F6FC4ED7E0A9738F9EB21B3247E49F5395A97A824108C5A962996691D51D8F", - "ldt_key": "836B00EBE1A2F5BB21B2A893ED31682E04AC369CF0963D6C0770355CBBBA37342AFB958C4DA2639D0C6B281F624C592BDE21727C16884D7BA21711D1707069CC", - "hmac_key": "29FB41D5F99AAFAF3860D7BA28AC448B388E64D643240E442C254D42D6AACC13", - "adv_salt": "E44C", - "plaintext": "7A698C0F1BF667DC0DA7940D5AA0B4276FF729", - "ciphertext": "4BD450836E530D172B9FB13F39E1CF154CFD4C", - "metadata_key_hmac": "03D0668BDD212753BC833AA080F209A21B5D8132747608D753ECB9CDC774E280" - }, - { - "key_seed": "5C450E249D3939EDF8CBD3139DD3C432EAEA58BC15D812245D4FDC89F4219B10", - "ldt_key": "6D34AA5E251A577541F23A7C8B18ADBEA94E918DB1ABF496117F273A270C6EFE1143EE0FD89A3B29DE381EB692084DEFF9C31E82D90E52C8AB9079AAD4DA65E5", - "hmac_key": "335B67C2D915D37ECF2F775426571A389DF28D1E948118F944B3818A54C46666", - "adv_salt": "A823", - "plaintext": "BB455DF842180ACD349CF983717B03FC124FDACD16FFDDEA", - "ciphertext": "E7783B07DAED46AFA5776B676241C523CADEE551D7F5BAC0", - "metadata_key_hmac": "B10C97AB9FA38F309EFDB36E8C33F70DFD0398CA311EC8E5C44D16FE57DCB19B" - }, - { - "key_seed": "0ABBD703E3F87A84F814A82D0775EFF810D0CD766724AD253B5D2A7E0E684550", - "ldt_key": "59D3BF27B0D72DB394BE06B0A758512997D3AB6C66B57F719723DF2B399AE219156C2AF670B261982010A8F8A91F7F359CF9DDCF5EBA20BC8D91647FAC28AD39", - "hmac_key": "D66245FD1EE63399A3E471ECB420796AC0D8C1FFBF67AF6F7D055A3EE32F7EA1", - "adv_salt": "D866", - "plaintext": "F2BB657EC7E3F7583B3BA4A8BDBEDD26E3D7699FFC2E65153E847AF0", - "ciphertext": "460F6850A542CA64A68A727824B9E053519EA01F399CAEE9CADA3024", - "metadata_key_hmac": "75D5D1B05A1B9B43ADDD5D9E1FA00FC76CFA56CAF94EC22FE3445A0BC60A9AF9" - }, - { - "key_seed": "16C1215117831095E9B4721996091C58C9240A82FCF2062BF59ACB4A5AC02AED", - "ldt_key": "116D8E1C85D0F4F32599D636BE3F57DF9DD0F08B102930206E6EF8ACC41D86EF868CB4A4E08DB482ADEAE610E1ED6A36F3C1C5879B88E786E03AC29047A4F1CD", - "hmac_key": "FE801751B81E2DC203719AE83F773CDB5123C60E2F32F18CFF22AE1E945BD0C5", - "adv_salt": "4805", - "plaintext": "711B2DB12CB10ADE43838D7838DFB2A7735705", - "ciphertext": "D299FA3B8D21B0FB0DDE2FF30AA5CD1DDC8D1F", - "metadata_key_hmac": "09FE282BCD62C2872FF1A2A40857E55198E99B163A8B2E74C5956642A1CC6303" - }, - { - "key_seed": "40F4674089D8D8F56CF4293BAF5F0FC36E55908623542080765E7FF5CEDFF491", - "ldt_key": "E29BF5DA37D2817BC44FAB3DD19333BDF6A455986C81492DC0E217402BEC6E013877620758F795BD41C8D1A1F89E8B72F3C42E9ED6705BFBFEACCA6E95EB9781", - "hmac_key": "016941DE37724E5066144373E82DB9BBD3D71A7912F889F68C3FD9CC4D534605", - "adv_salt": "0DB3", - "plaintext": "9EC1F5AF771E22F48D20249F90D4D9B62DFEB1321A101E9D73DC6448E4B5", - "ciphertext": "1F5D3CD8EAB5D8DACC42A839DB96C0DA3362FFC11A8ADE1C59540BDE4FD1", - "metadata_key_hmac": "FF37DC79D505C2628601DCFED56CF750E00A3F0C9DC2206CD8918AEB2C991EE1" - }, - { - "key_seed": "09A1AE393888C67C96792918CB3736DC2F8FA41387DEDCCF512D971F42ADE5DC", - "ldt_key": "907C4CA4714B49BFE50A05C48FA228F40E1181DFAE1362B9DE4AD5CF705EF627B6CBC1B8D8AFC606864147C38BDC986F99F1AA21BFD001A5297A5436C4218C61", - "hmac_key": "ED09C00530E639C727F5EC52CB9F8EDD68A754E73CA44672FC4B52A242187AD6", - "adv_salt": "49A2", - "plaintext": "03E17167B0304F9FBD8DB82B8189842DB3AA3D8681C3", - "ciphertext": "1891DF1BBAFBBE2E2F4C862C22282018B639A1603F2B", - "metadata_key_hmac": "AFA4D96BEFE2E957E0E914946301729C029F8957CF5AD5D596A902627EFA188D" - }, - { - "key_seed": "AF9DB6A25A8A5F0D23600D835D7111DE4E9B63B4864E65BED255EC2919C36E74", - "ldt_key": "B6B6A945F85914EE11E44665E0D2BF71714FCD49BD8B71B0DBC88B3A8301070B6DCD33957F9CDF4A7006F0ECC02D4F943F697A1D2E39C6825B0DE4D8E279F45C", - "hmac_key": "E63E95AD895F7C47DBBBDFE0E9F0966F68FF38DFD660A7D01F47C9CAAD32FE17", - "adv_salt": "71F9", - "plaintext": "6751240C54EF004BC3FA9C33E9DFC119055AA739F10824833625CA4E0216", - "ciphertext": "1364EBAD093E6C99789FC2B73F4E94A4CE02EE86434F44D630BB6D1B80BE", - "metadata_key_hmac": "683BF80D592878CDF4B44CAFE3DFBEC8290E549665A8036B5B4D079C1855D27B" - }, - { - "key_seed": "379790A3A16688F9A9B467CCEA5F7A326C24C943FA548762927D262357C2A4D0", - "ldt_key": "1F02E51C252D4F0DA772E048AB8D1F1940E911D7074876049F2748BA5A2D5E0366D4534280C5CBBCDE5D9F3A5AC2B6C7E4BDD971491E34E37CC7AEC003E2C45C", - "hmac_key": "70B0D103E3A17AA9F9C654D0AE9F32A7F24BA8077EC1B1A7EC946A73E78D11F8", - "adv_salt": "7AF6", - "plaintext": "39D25AB8EE2ACF8D6B925DB13694B813F6E9E3257B9D6E623FFE3BED8000E9", - "ciphertext": "5E54468B2DF8BE02F18F51BB0CCCC0CDD188C2DB524BC48AC0C8AB7E546F2B", - "metadata_key_hmac": "B1C909F56C97606FD765A2307EFFC78E083152BA417D379BBE45F65D53E9605B" - }, - { - "key_seed": "7244E9537F19F09B9E0B3B20EB96BED6DFBB284C6C1823D249A81D644181D41E", - "ldt_key": "46C45C77471DE10B1FC096AF2F1B4E50BF91E70A315E9F1DF80930994AD7B28887C991FFA51926E641FD0885DE7DD716CCF779CFF77111444B2DF878484E3A8D", - "hmac_key": "327900FAD35E7BC55FE085C6C1E1AAACFBA57B7D87E7D009BB1E216A64A829C8", - "adv_salt": "4428", - "plaintext": "76F9D208707E3576C1DF5B960E9A554FC47BB2D1E616A0653B2827B3D13B1A", - "ciphertext": "038B6EE79D23F216B980895560F7287144C4B355014560DABE07D32119FA35", - "metadata_key_hmac": "FC4700ED6C39BF038DAC105AB927205E6B4C89219B1612E61D109098E2178F3C" - }, - { - "key_seed": "A6D61C0AC7BCD56C6C66199C2929A1389C1878EAFE63076FFA36409A43BA1622", - "ldt_key": "CAFAFB9562C5A9F387F0A8C03D0E8AE3013D806486E2793CB4A76DC646F391CEB4F6DC28313C102E3414005414EB60664E3B11E93BC222ED1B1BA9594AAEF59B", - "hmac_key": "810F8F1379452CAB6D3FCDFC19D70C2EC1EF166009B5EBEDFA1924D39DAEA3D7", - "adv_salt": "03F9", - "plaintext": "E0DD037EDB87219B892C9C5A6E87C53BB1B730B8139D6ADAD200F7E4E2DF", - "ciphertext": "B3FD41D849FA82E9F3A0B32DA870ED2098290B5AB6EF5AD70260A9799C48", - "metadata_key_hmac": "0FA6709E1302364486231A1107AC491627615536700B48C314610D70EB4A6ACC" - }, - { - "key_seed": "E1D2410675097312A2DCC79F898D619E5334FD1CEC801C4C92598C2E481EF1E2", - "ldt_key": "AE7B6D9FA16122304F87C2C188ECD2397096236D2C6A6C866C92590012DDC6B56144B67B67F3C6B3443AC2305F1996C1525CD2E2391D6217DD98C48AD3F5BC0F", - "hmac_key": "1B7EEE453F9EEC77FD0CB9DE5EB1A62423B01A5F7158BF18DCAADE4BC1E9D3B7", - "adv_salt": "41A2", - "plaintext": "506C68217AF1FDE8240A5C581499647766061D845D7959", - "ciphertext": "4D5AE7562E3F2A08B8011B7BDF9AB1BEBDA3B292735091", - "metadata_key_hmac": "3C85C985FE3CB1D007A6E006E9FE0ED392F6721D460A14CC9F4C45D94CA26F11" - }, - { - "key_seed": "4A2CD5102101DEE0B9C7A5A0A3D90A17C6EB62D9FDE146492B1CB2018AB73F66", - "ldt_key": "AA5DE1D69FC58B0A102AE2F5185B57FA4391878B929690AE700A108CA027F9E10853E8CC884697364343015DFC5645743159040FCEC57C115B768155F7F2011F", - "hmac_key": "734F591AB362AF84FC1ECB2F20AA3A5B898ADFD8262E7BF51D4AE31199E324D9", - "adv_salt": "FA7E", - "plaintext": "F0DFE7532B16B3D85B31429FC849FCD5152CD16714770C0600900EF2C2", - "ciphertext": "3098A07ECEAA126C8D0CF51A5EEC21CFFD4EC4D87ED6D370F3249AAAD1", - "metadata_key_hmac": "69E5A6EFB346E39B928B380EFCD0DB3C12171C022CDA398D241E7FA75F3E7C2D" - }, - { - "key_seed": "AEDF65C5101442019724D8BA5A19770BB4E4B42ACA063CBAF971EA9D389F3055", - "ldt_key": "05D0A74C199E27F29192C6CEC7DC956D87717A96EF7DF42E61D6AEC1BEA892B406EA16336F015B8C48BD7D117C224D7F5D24E9C52B1D2741AC3FF19ADE5BE38F", - "hmac_key": "FC77044E4B28313A8C93DCDC6C94429ADDCEB92DB790D7149B5C78D277E18D5D", - "adv_salt": "BE34", - "plaintext": "FB1E97034125E50B7DAB98B5FD7AACC7EE06E8CCF7F44C77BE3009AAB4", - "ciphertext": "D559FF803F17B537C041D522CAB6E8CF6B72C2FCF217ECA62267582D15", - "metadata_key_hmac": "702E274ED9C9066C50D0E14B33F3AF6A3437165A3EE58F253334AD0A715DF5FF" - }, - { - "key_seed": "F859152456CD31A181628E7C987F1FF81DD5063757F5AEFDF3996103478EA458", - "ldt_key": "A719D3F4B3DCBB6ED0A9A64D85041636DFD5B2932A08E4B991D98A11E52CF26343DF496B055FA67E52971FB76AA634E8525B4C3AB49A770E094279F257CBDB9D", - "hmac_key": "3805B71A01CC6F4F3F04F5A855DED524B1AFAAA992F25AB6F58A67FBAD0D3410", - "adv_salt": "3AB0", - "plaintext": "190A6DEBA8A10730B7FB590DF7B5643E5EE5AF0FCC3F216549C9678B99FB0A", - "ciphertext": "3A11A58519E7550E85D9FC159FF99FC813FE0CEF7A81E4726DEF8E758DEFAB", - "metadata_key_hmac": "B5F0F0476D7875FECFF4A81A465E32FA42DDF11DB2DC7D56CC43A3010EE94231" - }, - { - "key_seed": "9BBE03E7F339F608122CAF6FFC7C42F84F13E2E60AB8D35678F1186EA48C73B5", - "ldt_key": "D20DD49BBE002E51FCC736BEFA614EA57798AF503AF91FA49CE58752556DE744E8BCE9417C25A14F4A4D518D6373FD6DDF46A9D1E5C9C77EB880C65672DBC2F3", - "hmac_key": "61A3E0DA748DA8C6950027C5C88C2DEBF730D34D363F2689C556001409B81B25", - "adv_salt": "7A02", - "plaintext": "DF9154B8C961A5F6B5962461C96CFCCD898F4FE1", - "ciphertext": "A7228D2DFDD4BB799B82F0B0742079AFD404EAE1", - "metadata_key_hmac": "6272353CE4F74C61571A21A536A1B3F72693B318865DB9BDB6234B755C7B89C9" - }, - { - "key_seed": "3379C24083B6D7F1CF2E19BEC671062FC16B05D05C0316CDFD8125B52685BA27", - "ldt_key": "28B693F96DE35E98588FF911C4D7033D495C150116786E2DD2CF0A65F61439DF2C28ED20D327537159C9770336946F92446337F448C28D81F00271871E557D22", - "hmac_key": "E4E45C15C730D3B65994671F11EA6AB78ACE91E79CD546948AB64CC74CC70CA6", - "adv_salt": "7042", - "plaintext": "B906E13C3DEE4CC03203C7CB8C320524CA", - "ciphertext": "C62FC94C2BCE15064DB15F6E10E40679D5", - "metadata_key_hmac": "A6A1F42E3B0CFDC4B6328F759DF98E8CE576C2B858E477D616C32A02907D0F67" - }, - { - "key_seed": "D4B7DB2FB9D813475FF7C49910225821DD841A82C42A49E7AF938430278AC86B", - "ldt_key": "656D63EE5608213E2D2AD2EDCCC84228D1139649BB0B5288488D7532D087526DB70454FEF78DBA5C69CA506A0385D6F693E6128F8EF0CB5A01E418243CA32E1B", - "hmac_key": "8143D313C451175B1AC1FF43C8EB95BA4817F8220F890D4D2D971D9192115DD7", - "adv_salt": "F65D", - "plaintext": "690114D595228CC8D7DD1C575CA072EF3FD5", - "ciphertext": "E1D6D17653346FBAAB461DDA2632C6528D72", - "metadata_key_hmac": "64B76FF204DCB39B7074281894CC092A016234E7AA68BCA117183A67B4D82D92" - }, - { - "key_seed": "C05773CBE32033FAC35ED3E6466C1323AF867CBDDE0A694937F2BD49E7F43328", - "ldt_key": "8E6838C833AD2533EC55858956B731F32CFB82CA67541F9B5C24D3B39EB4DA9D4CF01B1D9BBF5599CD6745202D02EE6C482B93B87B3011B0BB95497F25A9BD98", - "hmac_key": "C4CA1550C81ED8EF579738AF75851AEEC86B13F55C5DA9963DBFD0B076F37F78", - "adv_salt": "2237", - "plaintext": "ADE80DC4D6A916B09DC82B59DDA7712AF85B522CE3CBA2D52C255B82FE9053", - "ciphertext": "87A0404911184E56309EF8F19210D4044E3001AF15F6E33B60274159CF62B0", - "metadata_key_hmac": "9F198C89108CAFFAD798C53DDA166D565B5C3047BB418115A8557F797126B308" - }, - { - "key_seed": "5880FD7D91A93417C1FFE405EC94A19A6BBCCEABDD48D3BC826C6F279F104AA5", - "ldt_key": "066461A5D072A0EC2858792B929F5876301CF7C6145811E4EB6FF26A391C183B5D4574C0C13C6F87AF7C40C8F79F7D3B89575B6FF9465333530FFCC1DE68E34E", - "hmac_key": "CAB5F8751672EFB798DC8693B2C967CEE74C5586582B9C8F2948A18CA32CC2B6", - "adv_salt": "9CDE", - "plaintext": "1B24CFCE639A3F09B2018A7D96034474CAFA49E28E08", - "ciphertext": "9404526C7DC6AED251615018A8FD5A39BD552CF88689", - "metadata_key_hmac": "F09654197E670DAC944E0C3AA8885A40DF6718261841CBD4AEDF28A47CB93760" - }, - { - "key_seed": "103C51037466A5C87BBF1922B48608F383B454B711CD37002A7D37431557BB17", - "ldt_key": "6F4868EFA86DC84B1EB724C958C564324940E3B86D7A22BDC1892A7B61D4B6E79FF1D2BDDEF162EF61721BB754E30B2494B053B48316BE7908A5F296C4D0F61F", - "hmac_key": "018E9A83ECA054D5AAC2C71FECFE7B3352F585D0CC2B22C2854E85387436AA33", - "adv_salt": "BC4D", - "plaintext": "7502EAA2616A58982892655C4E90C8BA677D1B2BA6", - "ciphertext": "4C47A408ED86802FC9EBB5451E495095F1E967FFDD", - "metadata_key_hmac": "00F05326596F613BF8618381E00908494CEE2122AA57E96D5579356034B6BA6F" - }, - { - "key_seed": "19DD07C711165600E890266BA899E298CA1ED1B385A4F135493A7862DAA791FB", - "ldt_key": "7EE579175ACC9B076AA964EF815B6D34A4557083747349FA3853A32819859FEC9581C30AB2D8A520881F2DB1496C39B15EEE9CD70C81EB2FEB0D823CE5367694", - "hmac_key": "7B46AF4E0821AFC7260427EFFA2176F5D5F9B3DDC04D7C6C62F085BC1B8BA38D", - "adv_salt": "94BA", - "plaintext": "4F558DBED51485869A106CDB17E9209277314015D078286106", - "ciphertext": "335C337C57589E2CE14AD2D6A62588DD87B12D1ED87D399728", - "metadata_key_hmac": "BD6DDCFDB96F3033E408133E9F4649F69FB198191D7EED711021079FCD4A0732" - }, - { - "key_seed": "4C24ACBE8DB04793E4C1C930EF7E1699343BA6CEE1A77F7A3A7080F7E251B12B", - "ldt_key": "4AB3E205D5616A66E3DF018A9E5097833128C778EDE59956AB0F1FCBD971102ED3DBB8EC74C775ACFFBFA71CD0826703414962EF6AE830865F03F89730CEF8BA", - "hmac_key": "DEB362F55D37409F8994BC140597A2B3B869E97AA2B3C68C887EC4E92C979E5F", - "adv_salt": "49A1", - "plaintext": "1E9265A4D08FE3087F99771E6F0E2F15E30A2F7FC13229AD7FA6", - "ciphertext": "96C260845C844E2F9F97A44178961FE54B1C3D0B5D486B438CBD", - "metadata_key_hmac": "9D264877E55B60AD23B434F43BAF63F413B4E7D819AF86B782C9C7025695D367" - }, - { - "key_seed": "BD25F6AB07A65C22FF54D1F5D756483AD58531A4B197A08E815FB53EF0F18646", - "ldt_key": "82D32A9CFF0A74480A64F2E11ABACF8FFC634D88E1691B59CB4196F7013288A8949C9A3A937197FB4DD75FD0610BFAB2AF596A87129C5486E6BC9DCA39CB9CB5", - "hmac_key": "005333AC607D1782F4C15D328559F6A7D77A12EC58DB0E5FAD697056EF7B44C4", - "adv_salt": "446C", - "plaintext": "E80A906468574CB89BAFF8E52A1D51667D7FEA6F99", - "ciphertext": "D16305F7524DB1C300E6F54E58A23D0702E991E8C0", - "metadata_key_hmac": "73F68E09B0C66A2301CA983A0F97BE2502775A4E6A0FC079D27F7B0B098BCB02" - }, - { - "key_seed": "FC418978C0096847756F5530F89D00063F542E32B79579C002C07951435B34D7", - "ldt_key": "E73FA0935EE81321345637014FC3AD59363999DDE09627A7BB3CAED9032A268A4AE1D087F8EAE7D78AA1827541DCA66F99B5B310CC228E7F6E7A6A999A4E0940", - "hmac_key": "1B15832662B35FB725833CAB4131A05485B7AB975CE42D6D23BC2262546D6A97", - "adv_salt": "BE70", - "plaintext": "0450BBC8C51A4EBC692A4C23BFF4D210C4DF13769B", - "ciphertext": "0DCB71960A1F52C03470830C48FCE8A465E3A581E0", - "metadata_key_hmac": "E8E6DCF05303891D8B17AAE678FA58FCB0D368B7B7322FD39A98CCA0A7BF24AA" - }, - { - "key_seed": "2041180A29376678BA3151D8147C030511A73DBA688F75B9B8DF5CCBCBC1C0C7", - "ldt_key": "35BE7EB20EC673E9C12424863CFED35E91126EA77DAC8776256F0CB12918397FB459714F4ACF35CB3F69E0BAF7238934E556D6B7DD0B5A11803DFF5E1A48488E", - "hmac_key": "BDDF2F2E9052098ECC8D8367E57A3ED601AF07B300EA24D5CDEA34EC7BEAC3E2", - "adv_salt": "3B5F", - "plaintext": "794AE946285A473064DB37339A086869BFD1715597", - "ciphertext": "02F228E175B8771467BA176E1033E1420168B518CB", - "metadata_key_hmac": "E7031B66347209249DF4FD89D8DB2C106C0DE93343E35EC8043C1240CBDE03E7" - }, - { - "key_seed": "0DBA415E4560AE4A11EE9EA226E8F0557BDF49FC3087551836A41B45063B7CD8", - "ldt_key": "5F49DF5973924250986B9C0C1DAB8A05A04E37A6A19FB95588D93E93678A5A1AEF02A3D22819C0BBE403EB2D69B87F71CD001C22EED3255B966F771839EF4F19", - "hmac_key": "CEC27E2CA4842BD6BEB45A338B1E4AA9A4A3B4C218A365D9EB6A6653CEFD558C", - "adv_salt": "A23B", - "plaintext": "0D83837FAC4E96453C6157ADCEA227E3FBA12EB208D8D4AE5C", - "ciphertext": "BAE54EC7093C124986CA0CCB2E946C87ADCF4EA04E715DF0DD", - "metadata_key_hmac": "7AD8ED9CBF46444E8425E3A5D1C3C1CA4A1BE1305C337000BAF1AC9A177B700A" - }, - { - "key_seed": "BC06E8EC0BA473633FED05A99FFF8F319B5F39390062E1A8E214ECF89960BEDB", - "ldt_key": "23EE6EF691DB54DCDBF43692677C8081167AAD38A64B8E00394A86057186FA816F4377F68F268AD5EDE58120BBBFAF87F2AC58ADAFD9DA6FE04FA698466E4785", - "hmac_key": "1D023E11431A19ABB0F4A998F7C63737345FE05A93C94F05D984BC35A9B28FE9", - "adv_salt": "A8E3", - "plaintext": "2692F054D5BBC048E1FB17C93A3A7EB7F8D395C4AEC891EA62AF", - "ciphertext": "7C876CF1FFB1A4B8491D3E2D7568C4051EA1533FD1402F3AFA99", - "metadata_key_hmac": "B0A56DEC8D01319E85DBB0F11EB0D83B9786C40F586B6E8E59323D4D92272057" - }, - { - "key_seed": "94729F5E0F0DCC59434B93A0E0C873503747FBD39EB607C2ECC157A624C0FF71", - "ldt_key": "886E23DC1E672ECDC4444D462A9C7607022C9F049F312B9D56A4F7A80016383044549AC8F0D8B39F09E6BE341B9ACAC094176077C11A8B4AD9498888E744DA92", - "hmac_key": "17B67DA2B4BB2A3492A8412149B28C4608B97B58937D319A638F97D5A04740D8", - "adv_salt": "B2DE", - "plaintext": "C22F66F44DD1F346D53A32B3B86F73D1B6F8CC347EC6BBDEAC", - "ciphertext": "2ADD9C73EF5AD3A1D42DABCD759CC8BBE6019500A723D50A30", - "metadata_key_hmac": "FBEB951F1751A8912E7BC9BD30DF3650E14E0E44932F6931E81BD9D4EA82D796" - }, - { - "key_seed": "97853552152F9C635D179E68B151CEF51DAD18179A908D0AF77E431A8FCB2A4D", - "ldt_key": "655B2CD6BEF4DF670E969A9719F422662BB7550D8B81E7D7E47815C13510FA1AA66D8D2D6884EDD3FA0932E664A726D0EF8569888250B933EB982D0BF8F5CE01", - "hmac_key": "56BB22A258C6853321CE093F9DF6B2B09BE4850103197D46963693B468A3550D", - "adv_salt": "16B4", - "plaintext": "6E7BE9F6C7B5E8DA736541F6DFCF3B192A3DD80673534A285EDE", - "ciphertext": "1AB71BCEE930128847F36B784A8DB1A29CD98B4A39822697CFC5", - "metadata_key_hmac": "5C5BE24BB0A2C79196CBF3E24E309C139415ECE1548D91AEBF8A319B1902B071" - }, - { - "key_seed": "1AD10AD3882870D10712A9984F92FBA3CCDA6029A5473F90B62A3FF9DEE4ED23", - "ldt_key": "00F17B5F6487F2376F19196B905330C9CCA23244D6A0BAF3CAC724BF19226A0185B2783608DBA6A31CB4A2FA8C2C51B7D9632763773BC9CCCB399D69A62DD1A8", - "hmac_key": "9AAA6EB7664A9AE3C39469753CD27E3A28B1BD55A9BC2986497BFAB9DAEED6F5", - "adv_salt": "0910", - "plaintext": "747E8ABA603A3694061C8BEE2CB0FB665BCC4577A8CD87A5775B6ADCD30555", - "ciphertext": "51D689AA9EB209955D24F77402D1887D73AB0C64F8AF44B161ACF87B8F915A", - "metadata_key_hmac": "0E61826D0787C0B56CE2D4EC6412155EAE66CB475CB5E0EBF28CB9B433B59483" - }, - { - "key_seed": "ADBBD9D7DC78BEEB41DA9F651FBBC63900D3710AB350C7BF6B86B105A9529383", - "ldt_key": "AD2E0EDE35E70949CD1BA26C33E2B6D2D74E13DF583639E7FA90338847CF7DD4BB23ED634F9BCB7B9C1F882081525ECADD25E010899436B0C57B5FAF626368B5", - "hmac_key": "C270CF2D5C108729101561D8649B97A83088F639ED0B735B8405F4A1F2F1F9A7", - "adv_salt": "6C68", - "plaintext": "F7C24D90CEBDDD06238F4C21F925C3E7AD0F66E2D8FA5F1DF63A63", - "ciphertext": "0E22356768057409EFB7DE829ED923E4DEB21A1727DBABB4D7AA28", - "metadata_key_hmac": "86E4A13C61362E747698A54267540422C5DDDDB4A7727FC09812F2E521A30E69" - }, - { - "key_seed": "1A47B9AB0958B40D404ECF8DAB40A5AF0379810CC7ED13423355D7C4823993FF", - "ldt_key": "FE177A0CFBA6E16C413E3C9C5C92E73A8E29AEC3B1B80774F1A4DA648F88C701BA4B6F0A02B4A7AA85113610F21A3912A33C9D1A3F9D1A4CF4E6177ED7E334CD", - "hmac_key": "C03D5D6FCD0A6B5643DEDB532E36F7E333F0E39552BD7D7108030D04E3072920", - "adv_salt": "3FB5", - "plaintext": "98915F57FBE4928B727441B471351C0DBC8CC3AC7D9DEF47FDCFB454", - "ciphertext": "82EC5640AE09757F7C5EA7664D7ED8B7565D828D299D39F43FDF2D58", - "metadata_key_hmac": "5C4AF378097BB2BEFA10AD9237E84C0EFAE9C93C39A4CA9F57D72DDC67AD5076" - }, - { - "key_seed": "3B58E5F94544D95B3125D50E3269F098E8A6EECD22159F6FD87DF83C43B9B926", - "ldt_key": "00AECC8B7B786EB7115033A26DF5DE7D4E58172546C8F6F3528B58A4EB4FF0E30277C5DA73FC1F0F5821CFF61AB5F4E2E6BBF769EC9BA049DB4D489CD9ABD0FB", - "hmac_key": "92704BD960D4947751CEB1B956AC1E091F8F0867ABB594F701105B734998959F", - "adv_salt": "0887", - "plaintext": "893ACB5F973D542AA82494226310077D7F2E7E07ECC3489A", - "ciphertext": "FF2CB47ED8E2856634C93F8073A392339721195200EA5137", - "metadata_key_hmac": "DB37F8521FB8B20B0F27075A3C55BBD41C82C81B535B3522D6F93417EFA0B3CD" - }, - { - "key_seed": "0034249B125C14969C055AB6E8AD4BA5C84E22C966B5042CC0016374408F1B6B", - "ldt_key": "A54165E007DFA1D1222F8561023610E65DE26F2F3D61854A0E92E94C029409201CCB3DEB76D9F8442C1BD016AD9CB5A9D0818A95A7F64073BF265826DC8D1C24", - "hmac_key": "79E59673CC35398924A8C083006BA047919F097A1BA2BAD17E6F52435E7B85A3", - "adv_salt": "DB1A", - "plaintext": "A0C671ED2604B5714119F46780F0B954676E4A68", - "ciphertext": "D8621C93EA8E48913B6A8CEE365ECD3CCABC2B75", - "metadata_key_hmac": "6736A4C00A729980D08669F2E82860F0C3F9B5FDED7E1E74B0F83B4A0EF475BD" - }, - { - "key_seed": "55457AA6F640F046C1895D40A87D376907E8893CFFAED109DB1F4A30D001435E", - "ldt_key": "41B152812D750C330B6547B0CBB733FBC5B09D0F114ABC7D16B05C6080D8CDB25C838CC9727DB7AB15A50C7CFC09AEDE64AB0AF097E262EA08F97CA21CBDBCEC", - "hmac_key": "F12AF2C68C4D5442675432C3869B910A60A202FEDDAB503023B3B8EACF06ECE6", - "adv_salt": "560D", - "plaintext": "4253AE1DAFE28B8E50EFBA15098B93532BE965EC8AF86CF8DBA72363BE9330", - "ciphertext": "703A4D5320918CCE049D980BB7F8D47EA381DD2DBD65B5B83D4FE73CC10BBC", - "metadata_key_hmac": "F3346173FF7EB6EBF58DBE71DE9BCF946A1EE4176DDC42AF5641446846807C44" - }, - { - "key_seed": "FB650DC96511A841BED5A1E0E2354A588E776BD7753ACB1F8363941F93602011", - "ldt_key": "B73FC2649AC4BA1FB8A85AAF60395B10B473CE3473CCD7C13E0A8531E4DB43D5ADF9A501247FEACB8467C3BE6494C00687FB482392120D66589669B4F53B6FF9", - "hmac_key": "14343C6976F4CFA3DDFBC4A0938EF962E8B98AFA05E9E1508043497220E8CCBF", - "adv_salt": "AB18", - "plaintext": "837B426E7DB843BB0846492BF2DA7748E916", - "ciphertext": "C23C23A0EAA4736D6829B2DE63AC71B0BEF3", - "metadata_key_hmac": "EDBE5C4406A4A0EA52DA4DF82B1B024C515BB664879D3A7FA291E48349D0C759" - }, - { - "key_seed": "A36881200B80C508BBB899780C65614070D8E0997194EE3F6D98F23421B4FE49", - "ldt_key": "9588F448D9E4B82C81F4847495EAD92E4109B17BE5B89132A0AFC7625E5486939AD5B0347B086C353FE84DDD27019415915BCC9987769E77BA49D7388D43536B", - "hmac_key": "F83C76FC45AF40B179119FC6D048FD78AF5A08512AAA20C5F0C206463B35F9A5", - "adv_salt": "6750", - "plaintext": "A207FCA9EF439528FF350019B680F75BD4C7D8A4", - "ciphertext": "68D0D588C7E1552B306F08BC8D7C74E24933DD60", - "metadata_key_hmac": "E224004F5FF136FD43E448BB8504686E05C25DB926D972FED62645183FCA4C5A" - }, - { - "key_seed": "3AAC65BEED446CECC1127EB05936F9F99E68F6C30B80EACE4C8164FAC73CED77", - "ldt_key": "2ECEA9B27E4CA5F34BA9FDF2D4FC470072B76C9A679169731B568E8645B35486FA2FE400C2D4FCB3487A52391C5D7EB3130CD6495043350C1D5AF8BD2FF6F5B9", - "hmac_key": "81D255D34D3158FBFEAB4A4BE471456E9431F01A191E3567B86B7DC14494DB75", - "adv_salt": "AACC", - "plaintext": "8FB2EF0D058113BCD6CA3A0DA4702430FBA623CF93DBEF3815BD167328EA84", - "ciphertext": "8D638D964B3FA5DE2282900DC6AEE6EFBFC2762E4C64038A8930C53F3026F4", - "metadata_key_hmac": "CC4A52B10E528A93D651FB9A5A631AECE7F19601E5F7ABC86728CE849B132134" - }, - { - "key_seed": "86CED9BF7C9A488FD2EF946CC901876DAEC7AF7F0C74A09B0379BA12F2296CCB", - "ldt_key": "B3E6E90D7759351935D01D50E1873E124F731A1FC3BBAA9DF8311777936399C8A08D3C0CA11813322FC74F9916ED6617E66FA63B312718BB1E8D7D0A8E62F4EB", - "hmac_key": "E5968C6F4A11E1D4D9F54255636037C12143F1B500D9CABD99FBAFB2745D5367", - "adv_salt": "ED2A", - "plaintext": "E5D96EFDB293CF2525230EC26215671D9ED8FB8F2FCCF68937308B679B9F", - "ciphertext": "C4D352D54F8920C2704BBDBAD3E32BC81BD826FF9B2C329A9A5BC4A3BCD0", - "metadata_key_hmac": "163F4A8C5AAC4F380D601C6C233A886A22FCFA8250DF9D778FA5FA3B5EBE79F4" - }, - { - "key_seed": "5844A8BA6923B40A13266B3A5C87C0B3279B6B433D4A7E7B4A67146E0A7584B9", - "ldt_key": "E1AA576C09DC8153B64DE1DE9995E3A0B653EB33F397E66F85CDAA798E020E65BFF05D312CB5DB8F2664F1A6860545029C92A6D16973B62D25E43CE54904888F", - "hmac_key": "AEEF23403DA56577CF8D6CD29A19F17BA7FAF98BFF21A6DC3F6D5DFAE3A66BCD", - "adv_salt": "AEDA", - "plaintext": "099BBF9126A7BF666CBDAB15F16A3AFB6E096FEABF8FEC7F96586F58", - "ciphertext": "EFE54E8B8D1D4929365420D4F1B00BE2EDDEC12084AF888B4C25A349", - "metadata_key_hmac": "780651B63468124B784530D35C24936A6E59EA5727F616BA10DF38D0C0640AD1" - }, - { - "key_seed": "18810CEC96F7CF1DCF17F785FCF6E4B851C259624F99887BBACF34991B0E4029", - "ldt_key": "DDB1213996D3E8DE633F438EF570A9CB023DA04333371F34AF35754A43C5E511FF3D018D09F7054A0BDD6571C654A60768FABBCB09FA6A01BE98DA735D74D560", - "hmac_key": "6DE18531295E609DC755FA12D98B44AE58B90301EDDEAFB4DEC8A3C5AF306F35", - "adv_salt": "4F87", - "plaintext": "7465CCC4D2D461F0589C54D41243657C61D880", - "ciphertext": "7E40DE8C7319BF5895234E15EC0E8D6FF97DB1", - "metadata_key_hmac": "5ABB0A9776B5706C1D60B2DEEF4FB311E1F7D4BCCDFAAA5FA7FE56963D7857CC" - }, - { - "key_seed": "48A447100312BF866C96BEBCD04AC87BB6988C4BDB7F8DB12AA05BA4CD980152", - "ldt_key": "2048C23710EFF15C8826D2815933822ADD0EA25AEEAA3862FA2D491425B02A7CA64BE39B8BD0DD91547E8C4BD8094DF1DAB8D8F017FC5BFD548C661A648283FC", - "hmac_key": "572A5B8B8B3FF304F9FA05B67597043925D6EC4E74A00A12CEDE2ED9D1DF79FD", - "adv_salt": "6F55", - "plaintext": "7C37B54E81BB800BD98BEC561505036D43", - "ciphertext": "D7E3EDA6A499FB6B809C94CE9F36E031DA", - "metadata_key_hmac": "C2C54F1B79BC288D97E7E4ADB83091ABC7D3B400F2CB9B1ABE08650484EACC44" - }, - { - "key_seed": "6011B4A7C0618AB3D4E89DE71FDF5B6A9B0701144C954227BA61C2D0998829A5", - "ldt_key": "6266D2FB2B8CBE45701D1E170E12111E6FA07CD31B6D833104263122D9938FAD1044B8F727111DF64E1F82C79C097D544924EF61DB1683B9201DCDF0B5BCA8CE", - "hmac_key": "12E40307418404F91E740F274F79180DEFE22B6C42EA1D14DF6BB94BF142F85B", - "adv_salt": "095A", - "plaintext": "73373AD60B09116818EAA23B76315CA202A49D1A34518ED3A1685711", - "ciphertext": "B426BC7BA1E9554E07FAFBBACF6AA73D9D1D469BFF5DE009B7C8124E", - "metadata_key_hmac": "8E1E55E57883CEB2736DBACE6C04DEF4D280F4B9A8F69DC52504A55A8E381B5E" - }, - { - "key_seed": "B5BBAD9EFC6E2BD7A0C45C35042688F482CB873928C18AEB5D942565B18E759B", - "ldt_key": "80A136841226F9BF8BC1ECD3622189EF736067D622337F8A42C6911F85F99DB5A2E6D9850763F7301BE6CBE4C19AA7BB47CBE228E09877C97AD975906B7EB109", - "hmac_key": "4B92067CCDC4E3061C490DFD54BD67DAC1C0D51B397A55D22663E3ED1DEEB88A", - "adv_salt": "4099", - "plaintext": "A6095B50EA5DDCB5CC28B33F418140A81BE5CD072C914A3DE2F415272478E8", - "ciphertext": "EC0C166253B01EC19BE4D9C0B74B182BF7653D3611014BEAAFF77BEFEDC6C2", - "metadata_key_hmac": "9F4338DE4B1D6EE486F6D11EEFD38836C24FB5CD94F94278DAA469B57786C303" - }, - { - "key_seed": "136BBB96D2AF5550C57ADFB430735BEF3DC3ABA097D5140DA03D9303B1C5F033", - "ldt_key": "4DA15F9EE91E5B1E0ECDD1ABEE7A20DA93906CAF1D3265A4E2FA965AC038A7D52DE8865EF45135F22B1D5802A27775621EE6E9377D16DE803D6EF9A6201F5434", - "hmac_key": "43155F21AD97A0863DDECCBBCE8D4D7C97BA460C4BEA7825E889B9D3FE3A609D", - "adv_salt": "1022", - "plaintext": "C9934998AC1B1C055974618CA5BEF8BA67E31813F3CA8FECB6", - "ciphertext": "83BD9843A8944AF4FDD07F31B4BB591831B66B190B365199D4", - "metadata_key_hmac": "9B267AD54AFB8C9AD7DF31AB6DB159939660BE17FBAD1102EF760CC824906875" - }, - { - "key_seed": "A72ADB129B57EB50466073803CFA5F228799BCCB56B51E1D1308ECFA978209D5", - "ldt_key": "F8DB3117A89F29C02378CD6C56D8754C2642AB68980BA6CB473052CD5885142CA951278EBA85672FE178DD056DBF8EC178E53C8265C568D2DFA86D5C0C9351B0", - "hmac_key": "332086A93EC05DBE56A0B368B9AA9D71EC5F893B8979CA274C3A8CF18D9CBCAB", - "adv_salt": "8B1D", - "plaintext": "2E6425A8E6C5C35EAC94C8956389BE6C428E6B71C2DF89", - "ciphertext": "28CA4987C93EAA81A0AD725FAEA4997050A59F1D6FCA9B", - "metadata_key_hmac": "6A344E851CD0D2636CAF0B63CF336F266C42B0D63A1BD9A19AB9B9D37D968350" - }, - { - "key_seed": "E1A6C0886D409A10C782DAAC6AC3B092A20B9AB6848D9009833E053A3B32E2EA", - "ldt_key": "0B2DC44E38E77542766EE7DEF544505E362CA34AE2AC000CDFC631D1D5DCC0A20182936C8893B785A58B644C3F1827744209E747368DDFFFC0F4D6CB81CE7B76", - "hmac_key": "994D2DEE6B51B93F382BE2967D26D2883FA53D004B4EDCDA753340BF4816C1F7", - "adv_salt": "E9D0", - "plaintext": "AD5045A208D68370264DD1870E99FE894A", - "ciphertext": "C9B2470634D743A9C262D6B91DEF47FFB6", - "metadata_key_hmac": "5AD0D6BBAC361C553505ACE3AED2AFA72448755E07D5534513F0ACD5AC1D777C" - }, - { - "key_seed": "B4CB7A1612DC27664F812D5583A84514B522D8F4C8A67F315D0FB738B14C4840", - "ldt_key": "1B8DE912E11FFEA471EFE665C8F543A45AC6F94D0EC3C21FC562231AE116E6AF05D0AA66EB3AB02D2137F93CC62C6AAB88946E7FAF1D8B4CD7EF19B45A24ADC9", - "hmac_key": "D04F4BE422D7138EC4C1BB479CEB2D7B5F0CEE87A7ACD675B2C96F00FFC33C2F", - "adv_salt": "BD20", - "plaintext": "0528D4433F11A53C94DBC6590395F05881E7", - "ciphertext": "A93D5E5DD8873410CA0A828AD818C3211B77", - "metadata_key_hmac": "0B4F88AB71A780B90A54904D868C33F33B3B7FAED0B8C3806E051D0169074C27" - }, - { - "key_seed": "4437C6B000E28D91067704EDF087FBDDBA235DC00DE2815469E0E6899CD04BBE", - "ldt_key": "61FB5F999BA7FF93FA2A9799C888660F9324661DE1DD20A732D467348E5CEB451D222C6210968FD139BBB1E803AA91D315D1B2087BB2ED867E116C74BC9DAC90", - "hmac_key": "83CCF0E05425F30EBE6D9FB2600B4685630BBC05FEC12E72F79388EE4BD063DF", - "adv_salt": "6317", - "plaintext": "8D2461F68BF4EEA399297E97A23BDD000B990D42C68862E38F0215", - "ciphertext": "F062CB1F7552C6E703C5407B934E74BA1B4D365F7068E66C1EF4EF", - "metadata_key_hmac": "A3FB697D608EE59E62E21100212139351814D09A3BD6E173B2EB15D5B619BE14" - }, - { - "key_seed": "3500228F5C517580C4B666FCF0012A701EAC7CA13F0DD3B52DD9CF825B3E6AA5", - "ldt_key": "FC214F58E66050E9F735C368F791D36D5B88C81C8E5E1F39BD90E6F60A2C97C939368B80EF5A3D5AA4EEFF271A98D5FB9B4CB35632EF9B40138480E846D0F000", - "hmac_key": "EAABBA44E248C573DAA041BA3E3A8B55800274BC7EC0F0D562F65AF46713F491", - "adv_salt": "998F", - "plaintext": "1F63EFD8CA6C056B2DEFC12F3D7122754ECC8E1E", - "ciphertext": "2EA554485BD49D859EEB73891E3971158C8700BB", - "metadata_key_hmac": "6ED873A30DCCD7C7CEA004F7502B7F45930DCD0E214666B71EA0FA218F201530" - }, - { - "key_seed": "7CA62F11ED9EF8B92887FEBE67A18EA5DA89967A8F9F62CA53ABE599D7C6DDFC", - "ldt_key": "5FFD5F9530F6D75B096DC0BE00E639366C85CC8B67713C4B3820A5D4F50D46CBC8FE135F2FEBB00FB25513E8EB8799C57C2950AC302562545D2B44C3B688B56F", - "hmac_key": "47851C20EB7C6FBC5FD08C71967B08C287297B8A45E184A317B9B1832CC34707", - "adv_salt": "DB0A", - "plaintext": "B67A0D7E898411E0C116F810579DF4AFE2DE4A4C20E039", - "ciphertext": "317FCCA9F5A713E8F541C7180385B19DDCDAE9F78E21B1", - "metadata_key_hmac": "78D9F4E9A50F3D2E7A24E93FC54668AB1FDC1EC23E41AC3D4CBF724758DB4B0E" - }, - { - "key_seed": "BF598A4A835B0A7E9A17222757A2E8F52986AED0789886D10A05ADBD27959A38", - "ldt_key": "A22ADA1E227D9EFF9393C31B800B907E3910DEE1DD72D3EC39B1EC4844745D6AB4828A02F2762B2ADC33AF7EF94BEC8F0C9655536359980E342783CA31647FB5", - "hmac_key": "5D336540AD62E8151684EBAFCE140BDAF1ED1A7F84BCE7A866E413E13F5B9EF5", - "adv_salt": "452F", - "plaintext": "00BCECA59C0DFE0079E540ADCAECE3B7317D6A", - "ciphertext": "68CA2F327B8A61372376B265B92676C8213334", - "metadata_key_hmac": "843F297E787BC13E9528F4FF27E8E02D3BD1DBB7672681B1A0E563FD652F1470" - }, - { - "key_seed": "D9E312575EF085C178C53FC0FC07C8A36DDEB8379B8B7FE8DCA2FE4A4FE66459", - "ldt_key": "3C4C2F908DC0B34CC58D49F032F1D797EDAEC61E3BED6FA795952429A304285B1BA56B1EA4ABD562930B360574B2345C4A49E5665DE5B73704BB83949111EF65", - "hmac_key": "BEA649F9A160DCDA5E8DAF03D0920E7C7D49EE19235C77745A1AC007274B7F62", - "adv_salt": "6C92", - "plaintext": "A0FED2ABC74D08D3F5F67E342438BA85F826D6F27A9D1DBA", - "ciphertext": "45C95EE58DCA8BE9D404422B47CD050CBAA44B6D6F4B2D61", - "metadata_key_hmac": "76630985E02B91012AF9DF1297DBB2E57B251F098656874E2799E62DD49CE5CE" - }, - { - "key_seed": "0977BE1D83362E1C9E9C19085BBB1B9D8B9B238B9D725A534509C8B141F5D952", - "ldt_key": "CBB12180142008ACA58F8DB2988C0808B26500035EC26721681AEEA2A8231D00E3BA443204921E9836CB1325A8C872518FAD3E950F0C634B7A8B57BFFF280C8A", - "hmac_key": "925FFDE1A489C7602FCB4E0143099CF854E1164561BEFC5E267398F20168D586", - "adv_salt": "9205", - "plaintext": "DDD43ECCB002CD1A6C8472484D0D8256B3237C01", - "ciphertext": "D06F11B545EFB472BED34A7F95C57CBDA8BA8834", - "metadata_key_hmac": "9DFF4D616CE50665B79B1F921624A97DB55C8DBC40E0378E060A60E55A9F46AB" - }, - { - "key_seed": "1C4F80B40B6F1322CE743AAC976B7DF1081A512E8648DE8584263A45713BB4C3", - "ldt_key": "50AC714979125985143D95393F55AE570F680BAACBCFABEB064190673D78A46068729076E60AA03485DB1F5134C7A466EAFE8B31C10316757D65991893EC5693", - "hmac_key": "7013AA48E9A3574810E1D53B78495D37BC41443B95C38D2A22124325511D46DB", - "adv_salt": "3424", - "plaintext": "5E047CBF75F0492EC057B9222D56AF8B0228908BFE857EA349BBF3", - "ciphertext": "27177F6AECCD598EA2F1028E037EC82C7FC172D94640288D9FFDA0", - "metadata_key_hmac": "40F70383E050A746CF70B8C045E87B8CBFCD61F3A0578C2D6E54118B24C77D52" - }, - { - "key_seed": "53487B4FE763937DB3B5676D3099A65B47E8C7769760F9DE17CCFAE477688D9B", - "ldt_key": "4125C4AED983484DCA9BBAD115F9726DE8704F60AD2605813734DFFDBFC04B5C3F175796E6BF869D4F0C1B71DFFD8767B855631ABD951FFB5F682146AA110E9A", - "hmac_key": "5504B15B0D6A5EB2BDCE2379CFAF8B0A79F393C3D706B02E2DB0B8FEE5ED5630", - "adv_salt": "5985", - "plaintext": "C7AA4F926925E7C32B0097852B43BBDC6EE657E665B5", - "ciphertext": "00B93FF52C9B252B26292837735FF51F08F5AAD71D87", - "metadata_key_hmac": "33ED2236B3FD60FFCD79D0D0FD2BD7615522B5727AD01BFB4482E2E9C071F95F" - }, - { - "key_seed": "96CE52083A5A57B3EE83B2CFF216EC74B4D543CF348531B5D2AF0F22C5337938", - "ldt_key": "8C8A19C50EF15ED3F45E45B901A26B1EF2CA2F735B64EE56590561FBA6AAA34E3A01BE98BF21D0BB7F8C15B0CD0FAF673B9881EE46EA3BDD96CC179F3FBB75C5", - "hmac_key": "4E13FE8104E508E90C40B5E6798F8D2C7C66BAE2FB7D72172CB28C671ED91E71", - "adv_salt": "C9FC", - "plaintext": "9C5AA3363518A76FCA6F78A9A04ACA721C7686A5129E", - "ciphertext": "3A4720BCEAA132E763130979C2B667895D9A7144A43C", - "metadata_key_hmac": "E85B555DE907FBEE223ED40EB3ABB951B622348723F9C4AF1B857AF652518E43" - }, - { - "key_seed": "09914153EB8FD12E76E4C688D472FB3AFECE9092A5E569E95EDBA7C9CB060CDE", - "ldt_key": "DFD7A41FCD2E25C3CA25D5705B43AEFA82AED9C012F8B9A8A2D3CF4124420C79CC6F307A05B64A6DCE03D229DBF5B6F04751B117140F8258FE02605D5E16CB3A", - "hmac_key": "89B1507C021A21B16515F6783CBD811D194466B91D2204A80A93681B5902A92B", - "adv_salt": "49FC", - "plaintext": "367C77FF79ACE756BD9D6AAF719DCEFF2FF487E94D0660", - "ciphertext": "C9A57EE439E3E15FE5104DE3FFFB188C5678EC18B88F80", - "metadata_key_hmac": "D47827E3405E97253B2FFBF73DB2A4D974BE5D1AA2D4692794056A6D1EE409F9" - }, - { - "key_seed": "FE6B24AF4BD63BB961BE9E2028E915EC18B74F09A787A1D2EC09C8500D35A2D9", - "ldt_key": "AB86D686F522FAB3834EE921898D1BADE9E1B301C75623C1E30A12A7E50091224F0010AEBD1801FE111E48D8F99FC3C44C0268277F5B0CEB55CC5A83231FCB50", - "hmac_key": "C2BCC8076C7C57E59313E29393D54786663FD545D695CB369A6F91CCCEFA49D1", - "adv_salt": "BECE", - "plaintext": "E9D0C502DD9A6A82040EAD81BC9DC8A5", - "ciphertext": "8EA434C4F4DB5EB8BC863299D85198A1", - "metadata_key_hmac": "DC52B449E596BE9897D7676C5964CF0E6FC5DEA7E95C5FC08731AAA26EAB9F79" - }, - { - "key_seed": "D1ACBFF135447C0C8CF94717523538467947B56195529569A4F8A169B36E6AD8", - "ldt_key": "4E8B09B73126C3107B2B66B8785B6C71BBB0FC29C606B3F641E439C5EB58C0EBF356024097B3F31288124A757D663EAA21A677272C50CDF8D7D64CB5F05DEF45", - "hmac_key": "0831A40375B7C1612A606FA8EBCF8125BC6E19B50EC94F64985397FDCDBB8BD6", - "adv_salt": "F5B7", - "plaintext": "27D5412177348E37C3B1C89CA3AE4EB4", - "ciphertext": "8FF6C2131447193EE02CD925E1048538", - "metadata_key_hmac": "EA25CE77A100FF07AE5D3E13AECA7E601A8050C91077C7519941A45CAA215200" - }, - { - "key_seed": "8DDE63E8193F2C54E07E30D63EA79005B64C4310A31502A0C6EF724A7D005EFC", - "ldt_key": "6D8BCBD0229FAB2007EF3E0347CD8414FD59D62CE0673575390CA674AD4F243A9B918F34F892AA7A1CF352C7503EACC9AC2ED2330108D12525104C73A65423BC", - "hmac_key": "04B016619CD33C8D5C645E581CA9E8E2F3BCC9934401B446D7515099464D0D1A", - "adv_salt": "2455", - "plaintext": "B86C750825BB8631F571FD09AFF714832BE98F6FEBE9BF25C43E3D4B3F", - "ciphertext": "A83995D9FA47C31EEE6945ED27CBC122D4A50A7291EC9CA8C6CA6AE666", - "metadata_key_hmac": "5887DAFC1430FFEBA2A4540A36111CE6948EE1B4AB796E668949E8B67B27CED7" - }, - { - "key_seed": "B70DECFD384BD1CA6DD39DD7D6569A17C00AE084BBAC82A2497146D8E094B84E", - "ldt_key": "E45A75100B04409B36070A5ECB2A0F11BF1216FFE8803802C25876FAFAF8C68A980AE757C6B070FF9E300B6B14E86A727412BBBFE6C421E4F3E8FA6763C4F7D9", - "hmac_key": "6C853B742EEA1EE539CBF4290111711B8233A022C246C3D1E3026461A2DFB0CE", - "adv_salt": "03D9", - "plaintext": "FDC02E629DF6CABED313D140211D94C0D89D0F287CA7E0054DA2C8", - "ciphertext": "9F95432869D3DDF9A1A1F7FF297401313C9F25E2247C1DCBC64E75", - "metadata_key_hmac": "D0A899C00E9F2777FDC3E1BA7CD9A8E674F1263D34CC3A017E8C2B1FD011E425" - }, - { - "key_seed": "6F2C0C5D3755C70E2321BB72BAE671C57A32B66BB6F1EC65EFE4EE20B12C8449", - "ldt_key": "A8A0DDA015D08740BCE112EFC189DF6DA001327052636304B1ABCB14F1C93D54D7C1A6FC5CA4D0746D19816F7E563F7F0B7B03ACC92FE1557F98C4AF6565C673", - "hmac_key": "9AC72A8585BB66338301DEDA6DE9631BA1974BB8FD92F11B4164081DD5C9AEBD", - "adv_salt": "76EE", - "plaintext": "C04B935D3CCE7731E3770E51173FCA86650B3AF95276", - "ciphertext": "EC2B82DC913347C43BF8CED67FF6CA288751E853E7E5", - "metadata_key_hmac": "9394740B566FADE591DAF32401485D8669E9890CFF76F6F2CB96606353986BFB" - }, - { - "key_seed": "6EDDE96FCDE49C9F543C58453CBCE54014A53DF604C013AC8B8E56DC416308EB", - "ldt_key": "364C570E73FF40F476373829A6E9290F58C1930104524DA9C248B2FB37277770693FD3A5C234C87DEA87EF4EE972BC3F024F3654079D4CAC9ABA633668C3C707", - "hmac_key": "59A3A61F03ED79AF2BBA9B1EEC46CFB8126744B5CB92847E26635B9B21DDEBB8", - "adv_salt": "FFA5", - "plaintext": "B4E6EDDA091C2BC88DA3037ACAD65FD4F2AD", - "ciphertext": "819533A059FEECB490CD1334F9CDAC30B716", - "metadata_key_hmac": "A6BCAE247D01F70F76C69E7AD0C39DD108D5CE8A5CD1D069B0A2D5ECA33D9E96" - }, - { - "key_seed": "2FB448C0E6F94054D90E6923760D11AAFCF58A340F8353A48B9B95055E9B407E", - "ldt_key": "575B5B0E20F5FC215D445A8555A4D10B2F347021F52D373B8001FF3323A0395100D0C25D3F1736D80103495321C0F6DA15C2AC9AE2563C6D701CD81B09C6CF57", - "hmac_key": "209B89A340DED92EEC8643D979B1D5B5F9AE65DFB65B3DF414B10F1AF8AFC4B3", - "adv_salt": "6437", - "plaintext": "6BCBE18F9DB6D133FE1C7B21D955C464", - "ciphertext": "18783A571581F8492AA852E5185ED1BD", - "metadata_key_hmac": "A6E52A9BF231AB8F04EC4949CA45C116896D36810843D1EA630795360A4546D6" - }, - { - "key_seed": "3641F0DC64B45C0D2485367984CCEF2CF174ABE0E6D0BB8666518D4BE803FAB0", - "ldt_key": "42EFCC4880378598D34A51398759AFD9B0928E165C3AC53DCFC93792E5ED2C9DBE6ECA49A24B0D7CBAAB623D294DD082936FCF02F4044023FD2C826D1A41BBB3", - "hmac_key": "4A5697C22CDB879341AC594927CEFAF420172C4C3F29838ABF14280F707C6392", - "adv_salt": "5AC3", - "plaintext": "235EC0B6D300EC9CEBBD98755E8CC323", - "ciphertext": "03B020336DF0BCDB2511CE9AAEAFE8C8", - "metadata_key_hmac": "583FF8AE8062764675C513674CE42794CC2D3EE086E51BABFC565BE9F3BBA133" - }, - { - "key_seed": "685BECA6B5014A5DBB070913A8D614BFEB6525BF352EFD3A7BDE7D0ADF0EDC50", - "ldt_key": "6388A77AEC7CBCA7FCA99E7157583F4B7E6BB600E257DDFF4092D909F28C5BD70F93E68F707DBD20EBBF881D8A2EA46F4F2A1DC9492115554C1D5573A4A60081", - "hmac_key": "CD361086080117E9E28D669FABEB67F08A1BE234DD04611F62E84D8CE2F6C6D9", - "adv_salt": "DE31", - "plaintext": "2D07DFE1165CEAC2EA713707F6C36C3C6C6546A79BA91ADC05555CB2", - "ciphertext": "3F327602B2C3CBE5F8642975AB5A0784D2CDB2B8BF1C27BF711BE5E9", - "metadata_key_hmac": "9BE6EDC04FCE101B576A36F8F4AC314167EFE50ABC237AA0F9C9ECF01C3027CF" - }, - { - "key_seed": "0019B7D1FB73E265ACAFBB59FF225BA9C94108CBDEFAB4E0289E3F1DC8FCEFDD", - "ldt_key": "3F1F214F47956344279BAA9F7C65A59641B27B2E4590D61B5E94A7280A8AEB6842EB5544B0A2A4F53EEDFFEC35EC0C901C77E8E54787D8958542D0A718809DF2", - "hmac_key": "13D9A2C2C917058A252851D47ABCCB004A5F8FF4B23CAA2AE98859955AA3207F", - "adv_salt": "678F", - "plaintext": "03FC57DDE4A9650C2E5A7295AC8161C416FF51E674DEDC4B3DD281C0DC6A", - "ciphertext": "B81F9283A26F50E301B8F7E9D5D913DB1AC3880CADF9E0ED6921BF4B68C5", - "metadata_key_hmac": "0EA5A3D7BFDCAB5340C756D2BD6ACC70A3735C090C58E7699AB37B7FB4C58DDE" - }, - { - "key_seed": "488D217A78E794D2564F491ACBA28B0ED034A6541906BD375728E914D95D8AFF", - "ldt_key": "BE46614BE993DE7D226411658345B391019BBEB2D9A0DD0935FD34B0755F330BCC1D0CD1BD61FE81AC111333398BFDDB29B7D6ED2743CEC687F0A6A583FDE36F", - "hmac_key": "67C099001CB579A20688FB102A37B73F0465FB60BEB6EEB775ACC00804993065", - "adv_salt": "E73B", - "plaintext": "A4F4CBB2D2B5B8A19CC04723A6C7703F829D7842C57CB239DCFA0D5D", - "ciphertext": "9B72548B9E48FFF51F438F8B10806555E15F25CBD8663B24A34A06C8", - "metadata_key_hmac": "F7679F19AE53AC432FB8E869B7CA73B716A8FC5B541A0AE2B8372533F96457CA" - }, - { - "key_seed": "485D8F445B7B2C5E745B9B609CC0D244431579C7970060DC19CE8EE7A7426BED", - "ldt_key": "F075E4B12A85ED273AB7172B3589F86E6DDD5748AEDCE7C3EB4E51C5471669CEE271FE0DB894C93AAAA3B4C0DD724B71CCF4FA2B71F2BB74B1584E936C023732", - "hmac_key": "56232640F0F1DF1D3A016DD36FCBCB653078657118BA89CDD642D0AC167E53D1", - "adv_salt": "DACC", - "plaintext": "8D23CFDE6FACD0CB652539D88F7FC4E2C423DC48C4941C7B0EADBF3926", - "ciphertext": "508E83A2E42DA37DBE1691DBCFBC8A6BCC82C89EDE451EB742F0E39444", - "metadata_key_hmac": "ABD51FD47ED471A1C3E1330AE968D50114829FE177608AEBEEB32285C122E614" - }, - { - "key_seed": "716163538E5A30BC0B729AAAC08414840FA0670026770932E959D024C0E5D5F4", - "ldt_key": "06BE7195DA1F38BE149AAB2EAC68B0D696B4AF445018D24BA5E6760D057D8A9055A594F561752F6155A06697865005C0C75DC7B4B0BF58D457E6540270302426", - "hmac_key": "5A5D09412CFDAD3A5D45E5380A523F294657770770A44BBC35CFFF414B46E39A", - "adv_salt": "0FEF", - "plaintext": "535A76826D569EB754425239A6B06442FA6F2CABC86E9D75", - "ciphertext": "51A5426141361858F37284EB7063B9DC72548CFDC08746BE", - "metadata_key_hmac": "6DD2E45094D6B3EBAD158AB704650959A1B540AA3487E3A1D502B29F3C3CAC18" - }, - { - "key_seed": "33BB71AACDF4DAC6C324C119930DC5F2998CCACC71F6FBFB0D01B599718A5379", - "ldt_key": "96D9303DFB67749BF813230BCAA0A5D47155774C4B60676AE25BEABE0A0956B02F236066D8A31B0A6A76A50030A239A1F9A9BEEABBC1AD88BFF752F8E3479009", - "hmac_key": "9E6F8014FCDD1907BAF7904F0A201F47C1BDF4BDDBD1B955418E1018427E02C3", - "adv_salt": "6BB1", - "plaintext": "47AAA95EEEAD354B2B66430652A98841E98BB3C219A48043", - "ciphertext": "9EFF3A52E1B8C1E6A8F1C8BAFF20D44A5ABCA86138BE92A3", - "metadata_key_hmac": "DA5702D6A807202BB8E07E947DA8B0193F2457F5D9461D02EB27206B7199F47C" - }, - { - "key_seed": "232013418F8B9031EE4F9751505640DD4CB234EFCC785DE93F52CD70BA444162", - "ldt_key": "788D8B5EDAD8B6C5D44B7F1B28B2A06DE2D5759FB27D7A7648C53DB87B578459BE0265BD6F6A32AB277555D9702EEEE2BC49C5F6042C45BD212598A8897792D5", - "hmac_key": "BFE3BE2425415CA34F28827BC365DCE435417B7CF7DF7F1E803288125EE094A0", - "adv_salt": "F31E", - "plaintext": "E07EFEB6550045244D9827CBFB89891C0FD08029B56B", - "ciphertext": "320357CFFE46D4547F4853066F795596C2082091FD43", - "metadata_key_hmac": "A5B0D5F6C746A49C9C07ED720E2C701054971EB221516553D4D5856880C59E50" - }, - { - "key_seed": "23DFC8F778AD70A4C0C884AC825DCDAC443C1E579813E4603B38A60792411439", - "ldt_key": "1FF1F7C52647855CAB71E7863BA7CFF87892279FB3565A434BCFBAE75974987744A4FBCC0452E61DAF3D101BA4642027A31779215721470FBFD42431B4C1C6F8", - "hmac_key": "7188060CF40F2AE1C6C1299490C40724B1A457A8D35C092B724F65BCEDEE9D95", - "adv_salt": "5542", - "plaintext": "1C6D4D247AFF8238480811001C5AA4B0067AB30C389046", - "ciphertext": "757BEB6256874C7B2A98B3DA67F55B86C80E0136F1E220", - "metadata_key_hmac": "A6A0FFBBD2F80EF58F9EBAF9ADCEE83427A69B2F05997B5BC072121F036C932D" - }, - { - "key_seed": "875DF83728064FE79641949D18C2C61C9D34C13F3FB7AB8F239419058E9F9374", - "ldt_key": "684E1C82DBCDE7A034C4C5823AB0AF4F2FA9ED2F9A43065E5EB7EC17BD51FD1044FBB1B1C3FF920BEC1952F395C5061DD5AB5AE3F99A8998E69BC45827E61028", - "hmac_key": "8A50A84361709FF3BEC15A32F90385C70AA220F3B8809EB0AF2191DE941F36C9", - "adv_salt": "7216", - "plaintext": "5B2893F2D895E7BE7129100F96032E7CBB9D1161F2888F7A376EECEF4912", - "ciphertext": "639A0589557F3B11A52ADB7407EFBD77BE8250EA6DDB7E333B0E164609E3", - "metadata_key_hmac": "18CB527EC194B70A260DE822B875EC91EF25024A31324E43315F3A3541991898" - }, - { - "key_seed": "65219AE898F2F96E915A029F7E6710F4CDB346EC316C12219081351FEF7A8281", - "ldt_key": "B315231A39CDE17C33755E1FEC5B1DBA05507E4F7D11B90F4EE47767B59ECCB57888FCAB4AF8FF8328320A023A18ACAA516C88786E0ED28B6C61262B4918AADF", - "hmac_key": "B433027A9F895373BBC791DDC0B8B497D1BF04837A65998C0EC10436B52044AE", - "adv_salt": "C0F6", - "plaintext": "CF1955300119D84EA6F973DBAD44A200B174A9BF3A5A2149D1", - "ciphertext": "597DF4D1EE2A6E7EFDDDCBC3E0C7AFC6F025F53D8590C59169", - "metadata_key_hmac": "FF981CECE4C1478EE589AEB939CED3F38E2F29D34F7D09F62B492B7C9EC45204" - }, - { - "key_seed": "BAE9126590BE96CFF06E1544A2E8F48CF6B4A5B11CCEE12E2444A2C6BF741C85", - "ldt_key": "BDA2F3EB007F968A0849168D8112F6B3E792136501024DD838AB308A746D79FB5EB543B5EC9E3A2DD820E198885B847564B513BCE03EBE51C3FD4737E1B63D3D", - "hmac_key": "E878372A53B7BE8D20FD7E103A2643825772595FF0B8C5AC978FD5367B4DE35B", - "adv_salt": "0390", - "plaintext": "28FEEBA8F984FF274C540B0C5D2F2D68443DF3DEBE43FE5B", - "ciphertext": "6832BF61CDBDDB038AA95005792E058BBD2DA9C2E8CC64D5", - "metadata_key_hmac": "EAE978A7DABD6320E3FC862AA71C9D6DE9628FBF3881EB33C78235F5E4C2A34C" - }, - { - "key_seed": "109C2F5F20AD4F553C85F83A182A9D62851C95E69491C53B557A5BC6D90AF8D2", - "ldt_key": "8A3AF1C3855297D53CA1E6703A3F7CD5CB15307008A6DEB41FF717923571A75B678EBC74F0F6DEA14841A1B2B5BDE921FB893BDF6B3B1389AB4348B9B077FE9B", - "hmac_key": "1EFA63683DE03AD5064A6EE69A703258DDD915266782ADA713B40F621E97A689", - "adv_salt": "BDC9", - "plaintext": "9AD3F734157C17F1C829CBBB7B430190FD9B180BABB4E195CDCB0BB3E320B2", - "ciphertext": "DF537630E902866F6A2073E52064B2209BE1222419F11F8E7C477B0C290D25", - "metadata_key_hmac": "587C7ACBBC8EF7CCE44AA449610D88F203A5E2FA1B5CE9457F89238C7CE1F2BD" - }, - { - "key_seed": "0BBC490848590D4E07973036F913280A7A34E55EAF14B878C07B80E9D484AD3D", - "ldt_key": "E6BA55F41BE5D38F1570F4561602E02B225F99D122B433B4C90646AC2017CE07C8864FE1B36336E2E40B36FDD32F2D3F21E84BE10878200E352E326F6906FA93", - "hmac_key": "11D10505FC70D15013A546E32C6EC475DD5F8E9C6BF1AA9DA1BBFF20A703C039", - "adv_salt": "7D9C", - "plaintext": "1D83A3FF4BE2AE5BB09598EC28E77D63E73EB465DF28A4813D", - "ciphertext": "B7D30ED112ABE6435B08D936BB7159AE441B6B9367CBC2FE33", - "metadata_key_hmac": "CE7B627C481737ECC02486BC6C128609C433EF4E73F7CE150B2BF80437353A47" - }, - { - "key_seed": "CD96D439FE372D567D9F0EFCA420D0A2B32118BD30A8079A9F3A62190CC1BA0E", - "ldt_key": "9DD30C9B7FD8A11D9278BD1E6EEBA4A0FFB78B3421C38BE0F10FDF064FB498B66D1DD6EE7193B2E3B05E96D9AAD6BE3BB089F29155A740B26A9F73852CE7965E", - "hmac_key": "A56F9DA0A354559145B13427F306B6E2E6EC8393F158838226EF24149B4B015B", - "adv_salt": "5132", - "plaintext": "F00F56084310A93D97046C66F0ED55342C1440", - "ciphertext": "3A53A5FEAFA24F76BD376E44E55863E97C707F", - "metadata_key_hmac": "91F37258D9F2B052E80EA96DFF9257D36D8D6E59E0F0F42C86070C132741E1E6" - }, - { - "key_seed": "6AC0B7FA31FE70DE036B27ABB6532F3E10DADAA08F0AB48DAB6FAD53A0F931E1", - "ldt_key": "129862E2C4DD74B83885F72AAE50AE59A15C92EAE9E709EA79BC9E1EC1A4DE0094F52B790F08296EA1451A440A96B3161A0AECFF0356AD2C5C0C7EAB3D079131", - "hmac_key": "2A425FE28BA08A90BDDAE9530D99B1EA68EB50498FA5CB4CD1F66F7EF96305BB", - "adv_salt": "B882", - "plaintext": "936CB92494022DE43070F6DAF16E1D7DA2E3CA", - "ciphertext": "2DA153F11E24D634FBB51FA745836A59F94F04", - "metadata_key_hmac": "3A9B7D8F90BA011B74F7B8040C00DAAB738BB6FCD37DE15F3DCDBBF1E63FFBA9" - }, - { - "key_seed": "09F39A3914C684F46C5F06578671766E978C50FD36685B81E3D642A656AF40BA", - "ldt_key": "0DEFC9F52C67EFCFFA6FE18E769807594A4E42855E7DC5F753A389BDCABD97E73651D4D5696CB353950303C5F82AFBB05BC2CEE2C2F70A85D694D14863086D23", - "hmac_key": "D3534CCC6D4C50C7D368F917DAF9962A12B997D4C3D06C1DF663D4B79C36F322", - "adv_salt": "5A17", - "plaintext": "5A662BE3A033831FE0B8956E1A762A8DD614", - "ciphertext": "061BB8DEC19F63C11FE26D5632C76A5A5DEF", - "metadata_key_hmac": "D3957BD4E2CBE0846BDCAD8ADBE67FC48CD21C6FECE10FBF84C90D0CD9114BC6" - }, - { - "key_seed": "08CC65E59BE9634B5936A72589A61C008BF420A274F34430C50A1B838BC01CEA", - "ldt_key": "F92F338C61FF4F9F0CB3A1DA8C106A95BD361B0224D960175A6D09E0EDBB21F3AD8CE85169226E1ACFD7FEC5D7BA3940806725CFBB3C1050A5A0F38A90E9AEF7", - "hmac_key": "CD1C3B1E2F824475577CD4D15877A2A76EBD0F837EBD6BB9BCDA6A704CB5AD1E", - "adv_salt": "5970", - "plaintext": "A5E1068684761A0D70271BD1FE3873661B932B", - "ciphertext": "E2C22F7FA98BF2401A70A034FDBD4562B8A4F3", - "metadata_key_hmac": "A69562623B2C229FD9244BCB74521FFF607BA4A9E4708EB43E4E5DE96AA62A46" - }, - { - "key_seed": "5D05F0C3C565C04174FBAD35825C70EAAA93EDCF6863D63596A9BF34E52364AC", - "ldt_key": "F3FA9145A23FF47C252F6E000A2FAD8A238944C72935C095579A615855A11C1A8AC8ED5E0266DD24A2CF1741D9BAD88CFC40519D28B8DA06BFFBBB39D4D7C7E9", - "hmac_key": "85AE2EA76A1DC03FF6D159C41A156B4BA8976F74F1265CD6905F71FF9917F247", - "adv_salt": "0A50", - "plaintext": "0A129F5CDA6ACAEE1BC5641A71A4568ECB5CD5", - "ciphertext": "6B2BE584850E7D973B1F516A6859C00F455456", - "metadata_key_hmac": "C69F4FB11E701E21096BE0EEE182BC1743A4D863A0F37953C64439DA1C9D4AEA" - }, - { - "key_seed": "17FC70D50F24295D49A988C29359E028B6BA3B75EFA77DB8A3B23FE2B03695AF", - "ldt_key": "E7558B69103897B40C4569145D74E28AE29A96AA79BB1E487A7160710D82373A5A0F1D8778DC1FCD240A5D5EA93242312FE7D752AFED80B3E70046BC960C9B2C", - "hmac_key": "C1A66841CFF728515AD0B8C9E77AF42264AF8BA0CD1A9C3362024CDA68B4C086", - "adv_salt": "11BB", - "plaintext": "6FB7AF0C98551542E36C8EBC5D4C25D476B91E0ABBB39227DE", - "ciphertext": "0E847F778E48B88FAE811C2AE2BB51246036B2B51CA4F3D0C8", - "metadata_key_hmac": "0DC922B4E275B3782046CEE1927E1C4A0D570AFBD9FDF46973D7653AB6505E27" - }, - { - "key_seed": "83A488370765A337A4664233541ABAA97BDDDAE319D27B5C1E04E98DA84D4749", - "ldt_key": "D6ECAD695D630564E9B1B679365173F5B7FEC0E8A7F9C08810DE19C7EE3D69398C699912E1C4DD750D0A216685D6CF3E537444B929816943F768594294DD29A5", - "hmac_key": "3F5E333F6AF76CB35D472350352D6BA8657BBC96480CF7DFFD44F15815C9E622", - "adv_salt": "8FC3", - "plaintext": "3410E19366142F47480308BC477D2218", - "ciphertext": "7FA427047525AB940C045A6C0DF92866", - "metadata_key_hmac": "61E663BCD496891A9343771FDF3C4C563D47C7DC43CD11FC16C1306948669986" - }, - { - "key_seed": "B72DD63FA9D8252BF9014F95D839A4456DE0365C02823AF867C95A39F77FCF55", - "ldt_key": "4D4643E0743CA07CF45F61C8497409B46623C063D2669A34096BB81CE15652EB79A94AAFF31641ADDBF6509C705F6FBBE935A6C3F6A9A7819969A1CAE8A9950B", - "hmac_key": "ED9C18B859184698BF0DC9873921BF728541E2A2FC6AC1557683AC7713276A61", - "adv_salt": "3A6B", - "plaintext": "C8DD3D2910AA498BEC6F06707D6CBA6C06B714929C69D663", - "ciphertext": "FB89683FF049F0BC29903547C231A54CED45AB35B9DEB5B7", - "metadata_key_hmac": "927BF5AA80EA9FA2A1873D9A6A656AC9BC75368520D88C458E64B7715C0614EE" - }, - { - "key_seed": "950CCDBBC52B8907EA6A3826F08F5F7AE9B7460CE0796B2BAE9B1E3C27536E58", - "ldt_key": "D8AC57AE1F4F96C166B606DCC9D5D161F29DB96611EEF8AB10B6FF43718CD98CEBCA0F29BEE7BDF2CDEBB43630E0E9D40031290A7791055F8DE4FBC657251849", - "hmac_key": "923E93AE40F806A497C9D9AD1C047BACB1D96A10ACFFA45F90D2825B9DB81016", - "adv_salt": "EB6D", - "plaintext": "D6C6DFC0C7AE5CDCE58830B1FF4869FBE79DF2B61A63E700C3C0", - "ciphertext": "E92E58BDE7FF8C5817601FA3324F49FD981C8ABB3A3DB1223643", - "metadata_key_hmac": "6136016E27B91ECC645ED2A5EFF0E4F2C39464D56A462234EEC9A162F6004417" - }, - { - "key_seed": "B83A0EE452CA424AF473112778F4CA91F5CC4F86A4D3DF69C48FF5D125F20747", - "ldt_key": "2D65D82EEDABB27501C1645ACBCF2BB0B4D1D48125B179A20444984C0D9449FA779F70E82FC8CA1AB1F83E0C7CC2774EE589A36FCE75BF907C601633942B87DA", - "hmac_key": "3F837B23AF92192D5F1AD978A1331224CEFA584F0B22B078DF43E8DB7CBEE483", - "adv_salt": "9621", - "plaintext": "2243131E829C96967395D38A43D04E0080", - "ciphertext": "A2CBC17881AB92B05FEDD78AF267056AAF", - "metadata_key_hmac": "8DF19D5C532747BF2E6144C422456F44802ACC9C701F5E40ACA30CE72DB674CF" - }, - { - "key_seed": "087F657C20994BB468B4D1A0554DDAD7F62FFCD626112104BAA5EAFF2EB32A04", - "ldt_key": "71EF74B6B1485D7420F59D0FD9D9193138722159855D1750AD3E62467DC42FFA156A7E77FE1A7954FEEEFCD0A3872F37AEF600251FE5816553DBB0F978D14961", - "hmac_key": "7795AE62264FF7A8706FBB81C309C912FF248CB858BCAC99E1443BB7F1D60294", - "adv_salt": "67C7", - "plaintext": "5E2042B43DF34018929A46527B4D822B4AA4C60EC638", - "ciphertext": "A60C54419E962CE4C7AFC12047939E3FF219D2520D58", - "metadata_key_hmac": "67047E51091EB0927B2C98A442A95233B289AD364842547038EAAB94D7A1A55A" - }, - { - "key_seed": "22740ED4FDE15B558864234FDB558B107BAD955DC9A7DB8552E3080CE3C27C95", - "ldt_key": "B9B8C45E60AF71A00F770DC18D9E9C5452D52EFE41E217AB51F6DAD6169D756FA58AD7D55447D16B5A72CA20F7BC584CC033C0B4DB162267DF17CAB217099F51", - "hmac_key": "9DAF080402575FC679A9683740FF68C2467DCABF70570A7C32D5BBC8F538F697", - "adv_salt": "FB59", - "plaintext": "D8127D2968378EF5C353ABED92710C430749C65834AAE01C", - "ciphertext": "8B834EF490189F091F2E92322E80686D0A9514D84D8D1A1D", - "metadata_key_hmac": "28DE764F1F61C810E2B99F5733CCBF683DD7264587C598CE3F586B619716C555" - }, - { - "key_seed": "83B9B1B616864B6F5FDA22E1EDC9F8D21306B67F539C03284A17A6ABEDC6E3CA", - "ldt_key": "B34074F91686F78A6EB198B07695A81B48AAF40FC88CE86C7BAF0F224126C714EF4CC26285F582DA58C2B7B32A58E92ACC606178C7408AB5061DC9B31CFEBCDD", - "hmac_key": "1BDAA56D0E5CE06940CBC8EE9A3CCE1ED4C89C72E95ECD56B0941DC099BEDADC", - "adv_salt": "2349", - "plaintext": "7B18E0F8718B3F8C48E70709B2DA75011838E48A3D2D9252D7DF", - "ciphertext": "A25A5F69E9E0FA7F6FD44CB4D0A222A8E46869AECAC407391811", - "metadata_key_hmac": "D9825A3CB4DAC96669E1077E32262DD8172553438BF9661F68ADF497ECC35F8D" - }, - { - "key_seed": "0C54D42972E04ED6DF6AD67D7335CF041801FEEB27D4C1C4295D27CC39F97E44", - "ldt_key": "5420CB503AD81D477B3809899E5A776766926D60C06DA894A2DA06A0E898E19294F78921BFE7115688D34D389DE790843EEC2E119E075768F434EEFEBCFEBCF9", - "hmac_key": "6346DCDC7DB968D413C1F25532E4C813428B858C835E8DA3FD3ACB56A120CB01", - "adv_salt": "701E", - "plaintext": "4183540891E4E06BA22C7900ED93E2367E1EFEAD7C6E56552422", - "ciphertext": "7F8E10450986178E2A3D7F0DC5F5B9A61B39062BD4AAF7756581", - "metadata_key_hmac": "877068F263B8A8C4D1840D11690D47DABF1115EEEA3DCC04ECF8D901C8C5663C" - }, - { - "key_seed": "53DA12943D8D712ED58F30272C0DCFC5701CD65F0983430509338AC9DA9F3EDB", - "ldt_key": "C0902A392612ECFE565D8BACC7D2EC977CD90A205BAEB0CE6FB172BA7313E4D9E90029D80183475005462508200C698C0064069BAE43BC0FB79F6966D24C74EE", - "hmac_key": "3A51250C6BB80349A408338D6E71605DF2E2A81E5C33FF44CC4417E5E0542BC8", - "adv_salt": "7D6F", - "plaintext": "9219E2FF4234E8FD54ACFD6707CA2F01B14466A615D7BB4CC2416F", - "ciphertext": "D6C18DAF849217FDA4A1DFFBD04E35700DECB6F45D3B7A0DAF4AB7", - "metadata_key_hmac": "4EFB7158895B1118259C54CC78E31BBB248052CB7AEDC48EA3DBF9FD39296A9F" - }, - { - "key_seed": "1E6AC45BBF875C46F03D16BFA541F3C181FDC51C8F00277CBCE9735A04496AD5", - "ldt_key": "D1226CD808D45E56287BDC9F6F5C45118A83E977CEF98D5BF35E39D736ED9E8A027D9D8F91CB87EFAAB5875A76EAF426674D0DF3041ED675EE487B01B1C600CA", - "hmac_key": "DD7580EF1D7F8D122F5432B33E4C2911FB521597592DA98E417214187A445566", - "adv_salt": "DC95", - "plaintext": "A1E76EB381C8AD7047F9B2E67C2789EA93EBF172", - "ciphertext": "E16CD310310FD8457ECB96D1450FC0C096387CDE", - "metadata_key_hmac": "67AD4504949AFEC5C4B22146D1303075AD944E8EFFD79DEEECAEFE07BED7BAC2" - }, - { - "key_seed": "FAB8E36C5FAB89B4A67C62A5ABB644DA927D761C73DA1CB752BFEAE067A26285", - "ldt_key": "236FEFDC6DFD2A5005E380B19E29AB9C381B352E2BBAFC96EB39256B4F895E8251D6A4F8BEA0A37995E44B6C3F590D672CE8834588B61DC72442404D4A782F50", - "hmac_key": "85EE128C20AD8BDC2438B9226AF8D63B7299C430374987C9BA4F4ED377E5CAF0", - "adv_salt": "E201", - "plaintext": "AE2615F362002880DF066101987A5A247FCF0142FE6F4FF62A8B3659EB", - "ciphertext": "A51E655F1F9529D04969FAFB37B2D210C6B0100F5AAF7958617EA36A64", - "metadata_key_hmac": "2763E57A98D0A8B527492F8D6FB15890530F1825D6C8059AC0876A42A0F84B70" - }, - { - "key_seed": "8CF75065654AEDFB02C685D64A1CC210E762407359B6DF694D97529AF486374C", - "ldt_key": "E6B41278D53C9E476A4AC0590D6EA278E575796F1BF2F3E022F34781712214ACC076DE96F426124ABA1FE86C8B01B54C1F96D98542584A20C0D8ACD69C6EB64B", - "hmac_key": "BD06283AF2F0E776B88A753F20FD137A9CE1D213D6A893250E87ED014ECD8B54", - "adv_salt": "BDC1", - "plaintext": "4E63C5C8671534EB2B4063213D826D63C3E01B0DA9D4300676", - "ciphertext": "4CDB57F79D08EE51054B7B444F73ACBEEBEA44630EFC68108F", - "metadata_key_hmac": "EDE114A439EBEF9746C26641F2B4BC245FA140729FE3D405AE3CACD21F1722C7" - }, - { - "key_seed": "17730EC3D96E1263359B9CA680A08D56D3FC5056700FCF09F798163A250A4EB6", - "ldt_key": "8906DC897690FA9525907A8615412B7EA3398330EAADEF9E81E66EC60C57B06E278247B555260F9FA08FB8DCA30B029CAF2824F0FA3BACEC9286AC86DE6E781A", - "hmac_key": "AEE16B10773600CF83DF5438C878C6C6C2B88F800C0A86EF7C33D612230C2B8F", - "adv_salt": "F273", - "plaintext": "D1753D0D1C946B0675E0840CA9959B48FC", - "ciphertext": "837B7931396D61BFC40CCC3EA214F70213", - "metadata_key_hmac": "128F337336B15BF3217DC2E70921DD43B7187E72F9EBF20F3B078D76192F95BB" - }, - { - "key_seed": "97FD64DBB28B443B0930485D40C765613D56E0CD0A4644D2D99A9067483C3633", - "ldt_key": "61091495FD4558096DE0C41BE4B1A9813DBB412CD427D98F01E78394264ACCCAE582A3BC844AF73E959BAE7046833EE1C2C4CD2D6B2AD8E80232E18A2D286961", - "hmac_key": "37F9790651A5AEA01F66202839BE7FF6FD3C7220A5A2B4A37BB58A1CA6582502", - "adv_salt": "8EF6", - "plaintext": "57D3ED36ABA8C351D67AA527DCA7C765F34C0C9305133BE1", - "ciphertext": "5CAC5FB471CE1B42C971A05759BEA52F8EE020D3DE4CBCD0", - "metadata_key_hmac": "E2EE7CCA97C67B77EFA1649079D9232ADAF8E01FFF19C481B15EB4B48D4D2E03" - }, - { - "key_seed": "CDEEB09CEC920BD442BB0B3C38E1F3D324C444E2516D701B454C60B35FEDCA44", - "ldt_key": "320A5EEFABE36D8B311F5B25CB697DD0505710A21E342EF27CF81D3DC7C3AEC5AA64404DAA559F14782B0C9DE40D9B50E1334683E3224C248A2C243871C8E3CE", - "hmac_key": "6798896B6D3FE3A4D4E1F3078D3CE048B5C7BB14502A5AF467315D591414F34E", - "adv_salt": "D554", - "plaintext": "D5B92B58F17876513109A4F9A51C046E595345F87FBFE6054F", - "ciphertext": "93F45B6957AA4E7F99E5A5D6E2193111459644D663C8DCE02D", - "metadata_key_hmac": "BC2B7855C12150A3AD611E352006FD420F6AA49D490E131D41F4BAA09554B2A6" - }, - { - "key_seed": "546F7254270CAC17DEF49C7B77BB84A16957D5EEDB95A35C97EC05F9A1CEAA24", - "ldt_key": "92DEA1F347BC8675FBCF547C12C287B04DA4B40E93E2A0907FD0DD7E341E5BFD2312D343345C3487357632D956CDEE0F5375D5BF60A0BE9E6207ACAA23741467", - "hmac_key": "2D331256BCE9432E34A97DBE670523A778FBF614E1099698A5CB8F5D07198BA5", - "adv_salt": "73F7", - "plaintext": "66F72BA85D73126D5BAF9C7A0F79D2E72D9937A63382F7154170", - "ciphertext": "AF1BE54DEF9C33E2911171200C169C2CE377A7A8E61570DC7F80", - "metadata_key_hmac": "BDCC86C3E7260BDA5044A61BB60137BD2250D0CF46BE119E1D416A891319FFCD" - }, - { - "key_seed": "C0EBCD9AB79CDE3CC1ED4431AEEFDF545248027DCDE79188B88A8C00BD62A93D", - "ldt_key": "A0B70A0D9F9F19EAEED65C8E39CCBFE3FC8DB8D8A9E3FFA5AB27A2553F6DECA76652E481B77B6AF88A05F715444521F277B4511EF5D632B72956089EE728EFF7", - "hmac_key": "CB3236217C641E142F6B5D2DB1EEFF7CEF884071D75C71B4EAFD3836375CCD4B", - "adv_salt": "4B03", - "plaintext": "0314C8AD613D415F0381128238DD4D4FD43B", - "ciphertext": "A850382DF4F4B9C09518AAB95EF8E6578FCB", - "metadata_key_hmac": "0B0A39987EA7B620008F587D5E89811D3F7F72F0E7F015AF3D7B0985D62B1A68" - }, - { - "key_seed": "7579F96F2D8375DDF0E1CCC2DB73000868593D17ACA3F093091905EED1F9909F", - "ldt_key": "85AC4E459B6D5CD94C0FB8D736F7E83C964BEF9503809AAAC9397E2D808E12716A4F15E31134E6B4F845B70112BE998A0D1F89A1D3C971E83AB976087FA81CC0", - "hmac_key": "216D2C0FDF58F6D59E1BFDF1B008FBDCDFD1394D1110F79A75D4EB7D49ABE671", - "adv_salt": "AF8B", - "plaintext": "4E97AA3A8FC3BEE7E767C1FF9EA619006493CD", - "ciphertext": "9026B6301989334B38E41EBA57516A311EAEC2", - "metadata_key_hmac": "2D0604BD8450F53C0F4BD6226497F5A9344A6FA5D913D95901C0FF58984AF963" - }, - { - "key_seed": "B36D9182A1048F7C73E3BEBCD3A7B3A124C9C0ACE373DD4B59E0A16C71FA77E5", - "ldt_key": "356AC88D65AFD472CFE5E3F91AB0A6573404D3920C56A51636D0A5309B1B354E73915D3A9EDFCB08EB0A16BA997ABA8E28B3D0E977F57998C6DD2EFE5466C8CB", - "hmac_key": "A305DA096E08319A4803A625C42696D4FC295361B609493EDCF77381C43FE834", - "adv_salt": "C0B4", - "plaintext": "FE978ADA025F90A85B881AF60A2869C1", - "ciphertext": "7E71427B133726743A2E25301EECAC81", - "metadata_key_hmac": "83BFB085184BB8C36F59B8BD3E0C9311E0938F727942767FB0E071376DB3A517" - }, - { - "key_seed": "CD09C135BEDA8C109B152D9CF7F88A9ABEF5F4481C7488B883849FCD8F2646C9", - "ldt_key": "0D9F677ECAC732585B28759417855AF329A78590D49D9FF12D0AADD2B32781F0D9269746AE4B6728D2EBFF754122CA622C41023F44A23EF95DF60A0344B10066", - "hmac_key": "080DD4F47372D1E2436EC9571D0FFD206F7742270006CB3BAAB8E792CA1FB3A5", - "adv_salt": "D631", - "plaintext": "ED3D4DB1A7EB9237FB426029C6D49E45F150F7D710", - "ciphertext": "83E1F6AAD5F042C2A0C22287F3585F4D18E3EB0036", - "metadata_key_hmac": "87F0CE7CBB559F477FCE464486ED86D6A6DB6103C4806273B34BBDBF0AA095A1" - }, - { - "key_seed": "C09DBAC2B1BCBAB3D28B1DB92FE144717BCCD1EDC9103846BDB26D990D9F4B14", - "ldt_key": "68CEBB6BA3B08D27B8F47EB8239BA99C48C996283412830FDA984F5B7B1FA5E275748A94BBA20CDF3D85E046C6ED6DFCF2D30ADFACF3A8DA78E8517624E48D55", - "hmac_key": "7D6A1F87DBAB2F7BD8DC3F8B14F23E8AB22A222C0EEB69BFDB03DB4ACBDCBC4D", - "adv_salt": "F42A", - "plaintext": "0A6105CDFAD35964D8350847A787A9444778DA54A8511B76DB5CB399E64E", - "ciphertext": "903DD4A1499A7C5B3909EF18F724029A59739345CDA2A2C2561A6C2E4482", - "metadata_key_hmac": "3A94E95316819B7E7D72DC130C48D04E341B2AA17A81C78090BBBF0CCCAE78EE" - }, - { - "key_seed": "5442790FF7A9FCEAB803FFE492A02C0A77673CB8BFD44FB492B8AB9B1904CF2C", - "ldt_key": "402E8FCDCF7F998D019B831196814899A00F45F2D0C15A1BECB5F1229961B3F2E55DDC8FB99BC522179C84ECCC51670E97A301DF6DAFAB79B38E785FE5340EF5", - "hmac_key": "E20CA41C6D208FD704092DFC6FE8C92AECD8E09DADDC881839551E98361B9AD5", - "adv_salt": "9E11", - "plaintext": "ABEB4926C4EA95BA3248E47992D1BCEDFD451CB61D916264", - "ciphertext": "A3AED7A71ACA88CB7A88E192BE7DA37AA201B18D02E55374", - "metadata_key_hmac": "9796EB7412E34F4E7F9BBA3A5472160322260C0D0DCCD2689BFDDAEF4996DB4E" - }, - { - "key_seed": "3B87F7C71E02C5C0F6A16F6AC78AA9521412662AA59B8392ECD75C491FBF01E4", - "ldt_key": "3687A6075AD15455F9000009362B7E822CF7720BEA598B9F854F834DB5D304569C8B13E2AD25BC1B5C309FED0C21AA8AAE0E2EC88FA4C6615DAFF5820B0F7952", - "hmac_key": "2DB6782D5EA8A24F379E388B3152D43E74D36D79E45F76F63E567D4B77580889", - "adv_salt": "EDC9", - "plaintext": "1125A3102BB3F1EB5F7EEFDBE0AA7F090E23DA8BCD08", - "ciphertext": "4E44EF9D0E422340999130852A639A0135A7CAE80AF9", - "metadata_key_hmac": "E13C7E584F918F202F96DB447CA0BB57433E9232D1BFCEB4B093DD2E4F9255C0" - }, - { - "key_seed": "76DE95A76BD4D22B185A05245FE756896C06CAC50172CEDECD251A6DCA14CB0F", - "ldt_key": "9FA6AEB9EAC10DEFF68A8F2AAE2A10E1F6E5A749747337EBA2546178027508C402BA8C47CC1D97CA8B91B017EB00BA9056C15D1F008ADB4F446C00E13FE8160E", - "hmac_key": "B331A07FDC05AA8A9100D4DE7914E1127BAFAC4256147A5419ACF46229B80451", - "adv_salt": "2DEE", - "plaintext": "F7D625CF3BFDD089FB96A5BD65CFDE75D354", - "ciphertext": "174E63C64180EA078025CA9F65A7FC330356", - "metadata_key_hmac": "DD891B35565C42F8968A28C059C20250476E90DB46A666F429D25C1706070900" - }, - { - "key_seed": "8DC435F28B2814A95817D20F82AD19929EDD04CE6174915A38A68D55BA19C456", - "ldt_key": "8B6B64B8D7E041703D2D917EE972693DE9A8DBEF0A5846760F98CFE1E3641BA823F4803C2C2FD8C18B584D422192EA004D906FA232972231B21C5D7CA854C0CC", - "hmac_key": "9298AF5DF70C371D15C4BC85D44056D082FD30971BFA8D5BBF8FBAAC502624A0", - "adv_salt": "6362", - "plaintext": "13B76A7869694AF0F30AF57FF629D4E68513C6", - "ciphertext": "B12CDB5633D37650ECB922F1D1CA6DE2768BA5", - "metadata_key_hmac": "CED9332E1A888F4C9EB126537A98D2E7DB795507AAC88D9EA78E9980C2906B17" - }, - { - "key_seed": "A750D50F6DF9AACBD29A7FF6AB3C0E4C35E722432A051657B6F10641867230EC", - "ldt_key": "364B9811720C285488D1B613AA5DA0BCF5863AA1578F331A861B100830CF086B674A9C78769056C4B8D2FB2DE8E8A917F85B536C408E9AB86D2522E8728475F0", - "hmac_key": "5D617FCB6A3B9F8A334297FD136F12FBDE1F52FFD7DDDF211320485ED0EB9F07", - "adv_salt": "7A4F", - "plaintext": "FD94DB89F51B5E009998489265849007D5D14114D6FD", - "ciphertext": "E1A6627D1F2C464583BF4BA37B997DB7D616310052C5", - "metadata_key_hmac": "EE227D9831233372FDD260B0CC08BFE9C17F186B53509B491113A676BE6D3BAF" - }, - { - "key_seed": "CE558F42E9C5EC0A24CD5E3120E94FADE5BB53AB08CD965F485A44483D9172C4", - "ldt_key": "F93D7783046FF3A5B71DE731B7015E236E5E93A89DC6018B9D7B7BF8FB3BC6CE66BA065BEF5EBC2A8C0CFA76D85BD3FB77E12363A478388515EBD2AE737C5723", - "hmac_key": "1FB0C4076FB67BFCFBAF262A52DACF1A8CF31E7DEF62E39CC58433C80418CBA3", - "adv_salt": "6748", - "plaintext": "09E3FA552BA39072C14F59A9C1D7560B4EE042F5", - "ciphertext": "992C208FEA31EA2C09B1A27D20F333FD5BA02684", - "metadata_key_hmac": "93CE4B293C12CADCD0B9BD222DC17F358A9F5873F124A605B571818AF7D8C771" - }, - { - "key_seed": "871A0CE542912BE9D05297BC11036DCCA916AAAC6B64226867CACE2446F93C4C", - "ldt_key": "8C1D7F631CD9486D3AA58D6CBDB54BF9AAD43210347218F4681CDADF82E79D70387BF444AFCB3778205E9A460E9834D7284C921EAE62A079F69959C7DDE15564", - "hmac_key": "EE64AFD968DCC9E5C1C339E005442B30F8A6124ECB84B0DF015AE5BD0B3F7F77", - "adv_salt": "D9AC", - "plaintext": "BC22B0EC3188B9F4E1C47235D1ED55C559CDC426CBCEB4C8CDF76C86E5", - "ciphertext": "68FD17A33C0B395CFB5162FB41670C5AFF0914A2FA65D7C03FBA49E03C", - "metadata_key_hmac": "4E6EA4CAA9E9DAF62D939AA3459D87FEEDFC7F5E3F96FE588A82201D1DE34A0A" - }, - { - "key_seed": "0B1834A1CAAD9A446B96DA719E4EC817F1DB6DE42649416D5911A88A91D8D1BB", - "ldt_key": "D3F6A16BC42FB6E27CD897BC8AF9EA945D5A353BDC5EB781EDFDE6E16CA8718B4EF49F9FDBF2FBFAF8AEB7596A85EE288089AD445CEE74DC42579576710A5E7B", - "hmac_key": "C6DA07445FBA6B06B5840456B345F6072DE1D256AAA0AB0BF1D66728E49797C0", - "adv_salt": "18CD", - "plaintext": "57B8BED51AB39E290888DD88A457ADE59E", - "ciphertext": "B98ABA498DD64891EC4A524330F488A403", - "metadata_key_hmac": "99BAB3FB6F027D2B8FD851802C210E0BD6381B74C7877D54DFFDCE9E74E4AFC2" - }, - { - "key_seed": "95F18F784A69A10B7A6F63AE5C29EEE3DE033CD592707B9321A94705126887E2", - "ldt_key": "3F6F0B7E227A25AF15DA13F97B8530769E773D7B4AFD8B92A14AA7B75519F2B4FAB56767B6FCFC42151902542BEC23FAE133A79C6BDA3E63FDD9D8B041711F78", - "hmac_key": "0E08C9B0AC72EF8AD892658736BD93EE2F87506C406EE1E4E63C73CD3B6F9DED", - "adv_salt": "26C2", - "plaintext": "D9D0E3A4C12E2AF88AF51C74A898DE9843B707E9", - "ciphertext": "EEB57A21E15E485939975CA3D0D893D2B8E8E238", - "metadata_key_hmac": "5032FF4FA4AC443962F57E271FFFBEAA3AF5D8E947F5A50ECE4F224FC0503080" - }, - { - "key_seed": "695711816115D8719F85408548466F0E02F00F787DB12927E313DD9AC6CDDF75", - "ldt_key": "7F4A2174FFF86EF906B02ED7FA6146DE550F235A0D46EEFFEBDE6907AB094659427D5A5EA92302B62A669EAEA9034EFBB1A0295AC66F6906192109FC9858714D", - "hmac_key": "13FD534B4FB1013D6BCBF51825E3503048729794FA4AF57A21F92930BDB22B5F", - "adv_salt": "5987", - "plaintext": "60420D199842E47384A6760B99625537073113", - "ciphertext": "FD44230C154B407F203B4D068930418CE0E715", - "metadata_key_hmac": "FBEC4C555DE7E1AE2B0947969D3588F12EE5057CE0588CC9A1CE655A1263CAB6" - }, - { - "key_seed": "2E3F37B0235FE80471FB00EB4532B82EEFC634AD2EF7524ECAB169E0C79800A8", - "ldt_key": "5F1F00DA0AD4C64A8D0E59EC43B7DB6F6B14F455E4C1C27D1CFD81BF13D5C46F56A2CC80399248BC36E5B1774B8A02BC938F453C2E1B7D1B9882DEDF0B00C41D", - "hmac_key": "D7C6167DC04D9EEFA230EFE173B0A9ABE905C2C86D5F9B11B9207A0742B4D8AF", - "adv_salt": "B8B4", - "plaintext": "F7A09923A8CDFB5C8879E8EF96566180E1EE1103C123669849BB06385343", - "ciphertext": "A9E265E00D392435DB745962F8128C1C3ECB4B87D5599A985E420B5FE1DA", - "metadata_key_hmac": "B4564A26589F605669E51B58E5A9F46E997A4D3A62650A60AAB1E8DB76820A50" - }, - { - "key_seed": "765465BA434FDC5F5A13723AFC20E96BC3B1D86887C77B1FA8030C254EB92B9C", - "ldt_key": "8A7CFE1760993E348A87488A539F0C35D4B4F9B533DEC0A228211871D06AC7FC11F3AD456D8E0F108F27848711B2FB181112741B6E6981EC2709BDEB6383C307", - "hmac_key": "4B5BE48B79A53E8E61960F7BCE547416EFE321C2D06788360EEB554E1ACD3E39", - "adv_salt": "6F80", - "plaintext": "1A0E0C6CFC3A150CAA4D4D61E8EB4F34AD9A3AD36C15DD1D77229B", - "ciphertext": "64B7A5FE6B7C20F31A874AE148D4C97AD2E1CA693ECB288C864FEF", - "metadata_key_hmac": "966A4E64102369E0AA75FFA0D6772C90D8D3C3DE3483C3DF384376EE82D760A3" - }, - { - "key_seed": "72381291A62DE7DFD1CBC6BAB00BFDC5B46C2EE09C8FA278E42FB8DC42F1E960", - "ldt_key": "DA6715B676BAA8DB71D1F0775AEEF2390DDCBDE6ABC971899CAD0ADCE3027891073B76B94FA1A12CEB522085F78B3A0421003144F5D8B50AB8DEA5B69E696525", - "hmac_key": "B889942846482EED3E216C47731B035C38B9CFCF46D0263B989DF6A3A2C4445B", - "adv_salt": "9C9A", - "plaintext": "F711B422BBAAD271F03BDB9BDE48C3FC723C2ECBA0F5", - "ciphertext": "095B6BFC2CD29E3376651AF2EA8DED4460D4325B6905", - "metadata_key_hmac": "5E45EAF3F20A15A6DE3436DA60F8DED969B0111DB634B1F11FDD662C055130E0" - }, - { - "key_seed": "8E35D1093AFE39355128F04C49803450F4543DB0537B657C69C222300C72F751", - "ldt_key": "77C0FEDEDBBCE0D3E50987909D77BA4D70CC9C9C8B6112BCFD9ED4B8F5EA617CDF252E08052DCAB3B3D3C18F56C7413682838B32D415C55BB3F2B8039E01FD56", - "hmac_key": "5339126F2411B984EE956DBF1A4C265403297D133D67605A9C29ACF897043870", - "adv_salt": "DEED", - "plaintext": "81F0B5FDF2B425AF0CDC80B93A7A624F", - "ciphertext": "2312202B81C76EABE4E4B91C00136D23", - "metadata_key_hmac": "605CA950B80BB0E1055FEA70C503B263D7C919003001C5B8B54B0D5815F4BFCC" - }, - { - "key_seed": "1B0749CD1E244D4DEE64603769A689537C26B50BE53E37E4BCE1D3E10F582EDB", - "ldt_key": "89F12E3F45FE4B05B82D9CDEF43BC09CF87EAA058D0BDD4634BEFAD13D8F87B6F67C38C055AFC31BA2521947A8676855F757FF8C48AACC8430776F54E19341DD", - "hmac_key": "229D2FC414AC6756483E0E00CA7CBA34D04027D6D489522A97BF5E33F4E80FEE", - "adv_salt": "E2BD", - "plaintext": "B94D6C9912F72912851AB750BBDE5927", - "ciphertext": "486F60AC756B2C82E407232FFFBE7199", - "metadata_key_hmac": "C2964971446F3B1BAF92B561DD49412268DFE419747C5A8465A3A10721A5C1D8" - }, - { - "key_seed": "E09A7417E9877F581B2CF38D11D8D42F2B733C0A905429CB3869AA5727E68813", - "ldt_key": "96CC063FD11ECD5FF34B9581446AB922B1DC781CBF8A2A2494A9A8085F5354C44F59985797EBD94219BF3431C50593B65C19E1551F2BA6DCA2920495344C4E85", - "hmac_key": "81A750CA4967F0518943225CA422440439F71B14FE49044D1AD02AFB0828C279", - "adv_salt": "E60F", - "plaintext": "7EF48C4B1E3EE85E663E8C091975ADF32E52E0A4B7B5B3D9BC279CA1", - "ciphertext": "1760320AB9DA11842111E829802A0F85252CB54EAD7F12A1BABB616F", - "metadata_key_hmac": "3F6487B3DB83085F97BB68E6D1BE556541909A650481942A0708C0100DB90A72" - }, - { - "key_seed": "0D7C20ADC3EE47B9002FEEFDAC1728E552F93390B1F8961869C9FA3E20D7F657", - "ldt_key": "BA00D72C6D037D752B6E164FA60F060293301D22FE1106F8C921DB29ED31C05471585DC8B0F7D5C491C9DCFDD7BBDD14E7746F822D4503F8F65E95284115AE2E", - "hmac_key": "B11F2F2E03F7673E79DA13653AF3A4F76DA34CF0982B8028B143BDB8D3153F89", - "adv_salt": "05D1", - "plaintext": "258428977375A4EF69D086F2B6966A43299421", - "ciphertext": "C583A87CAC695D77C04319C0A3557DD2CDEF25", - "metadata_key_hmac": "C63B92D769ABC05808E5AF0FB9820928EDE040FBD81374FDD87DF4391C1A513D" - }, - { - "key_seed": "377773727C5306FAD0604DF77A07E9B4FE95DB4594938FA5E36FD05C67004A9D", - "ldt_key": "6F5EB812C88F1EA7A94D50E04AF00D8A818B231DEAB0D7A24458C8BFBBF5169EF5B79876C40867E1610102BD45D97B0F3CF5854B7F2808B25542F9F7C54BBBE8", - "hmac_key": "E61CE07FB912BA94CE24826E99AD7CF8DFEB0A84A97119176DBF539C63E80C21", - "adv_salt": "78E8", - "plaintext": "2E0A8022625345195F6B93C3BE8F5295F1", - "ciphertext": "AA24A9894EA51840333321662DE2DD997E", - "metadata_key_hmac": "4B3E7C26BFA8081C3DC82B243DDA891D1CD86A8EA7CD789C00260CCD9B9439BF" - }, - { - "key_seed": "1ECDF7739B0CE4ADEFED5BD2325DD7539D0A872AC95C1A16A77E56E3A20CF760", - "ldt_key": "1407D76C599A14A143446553628B4F8E3905872EDA141F245B148E69790CA5EAFAA7190B0C33EC21AB326EEA4D209914FD8D03E42E8669C04E5C1F7B60CDBE14", - "hmac_key": "BBD069445ADC2C90A6D9625A148B7B9A42B4A0161F9F87576FFD41AA995A2C5A", - "adv_salt": "F96B", - "plaintext": "A933A95E1D009CF57F083C8244C5FAAEF2E2AE5414367FDD6FB9", - "ciphertext": "44A5E01FC95050FAB258C1BAA50F115B10B65AFA5E309148EF68", - "metadata_key_hmac": "9408F5718C1BC41B68DE68B38AEC980EEE7880FFE2C8DCB42E3721448EF25DDE" - }, - { - "key_seed": "0B5B97066B4F30208B2342D39589698A1510246523220EF552EA0D292C9B7C28", - "ldt_key": "390E0246C707E055145F47522CC549AF6BA75CEEA06603002CAEC2226EC95FE54129CF95702C484BB3B09A80486E06E1A564825B3797A6419ACD5414A7538871", - "hmac_key": "990000714F5E6696C8A1796C927A103B3C4EEAF3A130318B69F459E0661103CD", - "adv_salt": "C8EE", - "plaintext": "BE3196B51A58523F04D2897AB5530E22469A08E6A9", - "ciphertext": "3B7C6736F04F41E0F80EB346E0F36377E08EC3C8E6", - "metadata_key_hmac": "A37DB2B4480C73FA5B9E8663441A96C4B4FA1248A543CAC51BB26E5316E3982A" - }, - { - "key_seed": "D18D84D25E161E6C99F6B883432A2615FE20C0820E5B8750578F77028B69EB92", - "ldt_key": "C08AA8161F484A47F912698A13246999AABC278B48268EB7DDB7D23DC6EA6462B3294D56522588D4F6F4E3E14CAE92150E47E8F9E009B6A33FC70708793826FF", - "hmac_key": "6584A1CE18AACEBAA3E102D9BE51B36E2CB9D798195D4EB20DEBCC6DBD8095EA", - "adv_salt": "E9FF", - "plaintext": "8335E424E057F7366C7AD90AB69472CDD0", - "ciphertext": "1FE2CACDC1ABA883BEE2F464B9DEBFB955", - "metadata_key_hmac": "1E8B1B63873F20CBA369615FB029630EEA11EF14D4AAF430370CEAADDA9036DF" - }, - { - "key_seed": "E89BB8A66D843D3A7FFEAE2DF3D711C962D3D2D9E34DE3D3BB0A8287A4C8F00B", - "ldt_key": "905307BCC3F3C82C84F12A9807F8DC1E7E419643A54328D1D5450D51A689D7264429CE85803E22EE21F0C167A010554BCF3C01791BCBEDF3BDC1F365350366AE", - "hmac_key": "79D5113BAC3A1FB4EA76909781CBB4DC06BF89043C373C9964489D175284937A", - "adv_salt": "D29C", - "plaintext": "9CE911AF013A1535A373C84F32B08837F110A668593974492D64CA3B7CB8", - "ciphertext": "1BF01FF3EE22F3FA0ED7C3FA6D5BE0716118937894FF2C0C5C0974BFD8C9", - "metadata_key_hmac": "A0ADB400E1CA8CDA1D9EB544C148742298403157A73558D6C0384071172244E6" - }, - { - "key_seed": "F580346EB8AAD458E302FB36FB9AB5993719F0D2EFA51FCBD5DA69809D61FFF9", - "ldt_key": "96C8DFBF3172CDAA12AE1E74DA772548B54A044F71E05642D954E1CD7CBE063F7C4BB3ED5906004A4B602C3BBB27AFD73D58891142D4BA2947B21B2BF269668C", - "hmac_key": "A48116ADBC1C5E620C163D0DE9B4F6CF37EFC4181F38DA6F575BE6CE8B75CA5B", - "adv_salt": "6858", - "plaintext": "B46BA10703C5D2AB82FECBFD6EF00FFC75840927DAD75F2F75D134D4E4", - "ciphertext": "6F59244143F1A032FD15F056B34A744EADB18855FC44CA83488C1D3C9D", - "metadata_key_hmac": "FFE03B929D4B11AADA631FC9115E754CE31155A0A795BF43F85EACDA2990E566" - }, - { - "key_seed": "93588CF34CE0255B2D35E75C948FBDE8C9B03807353B39ECAB013C8023C66F57", - "ldt_key": "84956017E5F5475AF1D43479DC65263437B3167EECB672F46169944062D7256880B99143B350C02DF23ACD415EEA6B5F573DDB65F399E25606CF0BE12CF400D7", - "hmac_key": "0E1B448C6D28C2A492CC93CF32D9107A3E897E8044561DF6F2BDF87DF1C5DD8B", - "adv_salt": "992B", - "plaintext": "076FE4F24088FCCC07B0154009C5B4078C9784D0952FF95BF4", - "ciphertext": "31796F1230A90B220990D0F10A209F80EF7A9AE01AD2ECD2CD", - "metadata_key_hmac": "44C00FFCECCB08934266C91A4B7685186EF150D405C5A91842DD2C6E8F789E02" - }, - { - "key_seed": "2E86ACBBCD7FC897FAE73F3A2E9297DE135C2FBA92881E8004C24080E1DFBAE5", - "ldt_key": "7E40B0C48425927E5789BFB60F323DAD9698AA522281A684FF92EABC311108DC3C6D957CC7C4CAFC2A9F19C1D59F6F11BCD76C7D464B0856CF81BC822834AA86", - "hmac_key": "B5FA05B652BA6D2668196DA9B8D0AE6CDF2982503FAF000B90DC52A2473D98FE", - "adv_salt": "D06C", - "plaintext": "D0B9C548A65940C763D95C3A561D8979962E4BDB2C2E", - "ciphertext": "625CF9643EC69F218278D1F2BAD2A0154BF6BB2A8A26", - "metadata_key_hmac": "6CB2C2F544FBD75C3D875414DDEF01E2BFF2D1B40758C1672573A5E0213B8CE1" - }, - { - "key_seed": "2FB0EC5CD9F469174A96F1C14171A8E6C67BA0D56C2FC3A00628B713236B9E4E", - "ldt_key": "EE3FBBA11905478EA1B1353DEB10634F195F38FA133D53360C25607D58AFA6FE8A88B9F8C698AFC45A6B429AB0F68A9BC6B56EB385715DB2F27129525DEC665C", - "hmac_key": "0637BBCB8D173919C986710AE11CD6EEB83E46EAA5CC5C429CF46DF71A8F6058", - "adv_salt": "BEED", - "plaintext": "02E4A96808C95765A922CFB0D0D9ECD5C0B49ED3384DE6", - "ciphertext": "4A690E995A954F7CFC7F13C5F5ED81EFEBB4230D733C2A", - "metadata_key_hmac": "D25F03795C05EE864A4312CE1088ECE931116CC078FAA191C21657E256369833" - }, - { - "key_seed": "37C170756E293F3F6092FABD3EEDCD9DEB2519610214B7C9D7C417719BE5C6DB", - "ldt_key": "FEBA46FBE1CB8BAD3AFC628E8A6A778863511EF9BCE2D652B9A4BA49003A76750BE30417558931ECF3DD2E636E7F2837437C094652F80ABC40BA5CE3EEF67449", - "hmac_key": "1289ECB15BA013589A2226403D1635FEE9A72BF37D7FFA9F284E14C645EC8DE8", - "adv_salt": "075C", - "plaintext": "6391F65414678673BE8927A26FDBA669F3C256", - "ciphertext": "7445D71AC6C0A8C838E4A55D5A4F6D13CE9FFA", - "metadata_key_hmac": "5E9307F5F712F0F32699F093B769B8D2D84B2DC597F4CE2CF4E1DA0F171DCE52" - }, - { - "key_seed": "45619F5CEAE4E2ED2EFE4A90CA066D369AFCE0E480BC244C790AA37BA8E70657", - "ldt_key": "6F19141F07631BE959AFE8192B43AD51F84F3531989F94FEB68A347CE1265435E5DBADC6B8C3D495780487EFE89AFFF7E585D26E3DDAC8CF89A34992AD4A4EC2", - "hmac_key": "49A10BBEEAD8F2D1EF0847DC2312A02FE9907EA220440F265D9D976E29DB9CF8", - "adv_salt": "FAFE", - "plaintext": "AF17661A188E8D91698FE12DCD5577F9B560C562A3FAA88E134C30F17E", - "ciphertext": "881080FDBEC85E7EF269CC29F0977B79C8386E848878531F3D11881945", - "metadata_key_hmac": "9C789142AAA3372632DF23547C07A06FCA18B01EFC9009ACA64983470F410941" - }, - { - "key_seed": "A393B059FF76B55997A6428D587F0309B4AC707792D5DE91184B73C07068FE14", - "ldt_key": "526DD74FC034373B40E162522C7479C014F1344136DD8B30FCA1E1D3AF92EA971951C6A1CD0D28B3097DE4E03E59053A77D7473CEFB31911934DB1B81878BA3B", - "hmac_key": "07BC114B204E229117AEFBD1ADF520EFE2145D043CFBBDE2B9C5B1330EDA331C", - "adv_salt": "2417", - "plaintext": "92099CE78A30E61F84A476F509CD2ED46BE9F43D7BE338E9FD3EC406", - "ciphertext": "6EDF8279E45D9FA0A4B76864BD69AED8E52601192A330BA9AF1F58C2", - "metadata_key_hmac": "6009E34AE82667777158A2D51650AE2EA688867F0AD4B0DEBEBD3FA6B5E723A9" - }, - { - "key_seed": "67967A06AEDC8E27B759454391BE5BBD5BA255A2EE23C40A9891317646B0B4A9", - "ldt_key": "47CAC71B39CBAF5759EACFCCE70D8644C0AE66E20F58A779C3C4AC6F10A23A9148C8755D25219FDCBD5D8CAAA8178606DB0A0A1C14F3EC555628CA4F4DA4C207", - "hmac_key": "2C5976A0843A1B73A9EB4E223EAFC414808D5A6480DF301F7067DAD2AF4CA709", - "adv_salt": "A223", - "plaintext": "ADCA492DA05FC0B2A2733E94819194B3A34E55", - "ciphertext": "4A946550724ACDE397E4DF825ABF8B4F7114C5", - "metadata_key_hmac": "A0EDBCF865034CD43DF4A545D0F7BCA967C564ED9E22BA1BFF690216816D5794" - }, - { - "key_seed": "90E39F77C5DB43864F1F88A72F0C882BF78ADB49C04ECBC022467D612E283A13", - "ldt_key": "435DA1AFE7BAC5D20D5C4C741CE67DAD6893EEB367F9D30E0CA0F09176A3553CC3E0DAA6F5A2C7D0DAAA8DCB2BF6F38E10C06568CA03C3F8315D7635FF4CA4DA", - "hmac_key": "946F01A314CEB6AF1A852E70370C3072F65318D3A3AEA7778943AAE81B614E9F", - "adv_salt": "0CCC", - "plaintext": "A4F9CA00FC38B02FB88D441C26B097B7F27431", - "ciphertext": "C835E4918302374E1346A8B975018D16051020", - "metadata_key_hmac": "A6206935E82C2FA100EABD8306F0E5C78E17A3FE1F9D7C4387E9DEC4667A9924" - }, - { - "key_seed": "E8D9B87BF76DDC286DE441207E885CA36DBDB519CB7219BF540AA658700B7B2A", - "ldt_key": "77275D5B7AA5E9BA852A7D3B09FAB7BF58A259EF133B794D444B6E69F8185DABCA140174BD4DF7A3EF0B3977E404ADDCEC8EB9E6CC9A8B4ECD663CDA32966E77", - "hmac_key": "176FC5689F1FF116CE5E401EBB9B6D3EC4698A6340C97D8B96A6FF7E82FDDFC6", - "adv_salt": "EB0E", - "plaintext": "A5A56CE0819C10334DDE2E425F82655EF6D6F768901D81", - "ciphertext": "365D853B73185DA663CF7D7D51A86436306057093896B9", - "metadata_key_hmac": "79F8C788707F75963428C2E4771A906FBAB25F42704AD61C09129B97DF28BCF5" - }, - { - "key_seed": "7367018C066EF078B706CD8DFC2B4044DEF189682651ED9093475B667DB2439A", - "ldt_key": "97A061889422F49AFD64C156588A0A81108932F885C7577CEB91D036D643442E5684806E3BA6A5BDCD0C11E54FFD820F1498C8348012A8536C5D1E99FA3EED6E", - "hmac_key": "02030AE5A2A63059015E50725C29F7166E5BA1A4B97D80F0F32CF04308242661", - "adv_salt": "86B9", - "plaintext": "39C22AB75E16F11F539E3ABE96761BC4F2B17A", - "ciphertext": "76E96E8A879E01D3A70B24E689464F241BFFE1", - "metadata_key_hmac": "FFF91740C364D52B8C244B8AEB77365CB289A40E279F5497DE9098CDAE7CFEEB" - }, - { - "key_seed": "81C509C483D7A1C427DCC5EA2E05CBF4588FBD984B5219DCEAB11741FE761DC0", - "ldt_key": "64C2A9364F5792E39D244B8FF3CB23F6F0593596BFD8CEC89FEF9BB2FD4772B4D708018427DC658A2E1855C7DEB9B3892B991ABC02F0273394BB92D4FC32B945", - "hmac_key": "6493D527762752CE49DA792118247B05AD5DA653994309DE64BE6098BE72CEF5", - "adv_salt": "E1DA", - "plaintext": "3A1B6581737EAEF0D68EAE52E57BA1B989C18E59F12336F4", - "ciphertext": "FA57FC03D94B1910FE96C7F303454BDC96C293BD1D80DA21", - "metadata_key_hmac": "C8A153B4A0D12079F8EB03F44F8551AA59C25D7BF5C5CE25FB08883895887AE5" - }, - { - "key_seed": "98E720F7BE4AA07F9B457E53E87602FD10B9198A0B67194E3685AE69A6CD8061", - "ldt_key": "007422437E2CA078E7EF7870E497B2F7DC9161EC79FE046ED1ADE1C29D26404113B70C2180CA36376D25C37088DE4DE2A4E7213CE1AD50C2D52182BE5FB80737", - "hmac_key": "21FEACD34FF6D92AF01D10B2940F0E2DDDB373048CA9FD16E010C330CB31030B", - "adv_salt": "A13B", - "plaintext": "934B45CB11DD77578E4AE09AD554B4EEDD14AA1BD022EC47FBCBB0F2AD3CDB", - "ciphertext": "8CFE890A7864CD65091DDC85F7E0CD9661474622EDF2C0D7D44A1EEB31501B", - "metadata_key_hmac": "99CB7E7B8DA309853B0E34220D9A2B7CEBA5E4E5421A1DF459028015791BBBB8" - }, - { - "key_seed": "869A1CAF84F8C60AF1573BD15118E6C83711314495ADDAEB86E4A10FC9BBBD4D", - "ldt_key": "CCFA059EC7059537D0C7F627331C54EA43F4FB2473CA24288C3436C6F496E3A403D1F31B4FAFA9AEBCEC663F82F0E54D8AF59A718CEDA93AA4687F79EBF1D52A", - "hmac_key": "D09919AA79B853568687340D28461E8778C6450A03098A4634F196FBAEF9B3DD", - "adv_salt": "7A78", - "plaintext": "8A5BA566981761C530F59FF7A5B76F7358ADA54DDCD6", - "ciphertext": "E2EF27BB3DBAEDA0CF508F9178E2F97A7DAC0846BC3A", - "metadata_key_hmac": "079AB6E5A595FC2EFC8413F6469E6D4B286A0CEBE67B2990B3B6B596D04E9DA0" - }, - { - "key_seed": "5E114CBDD861FBB10B285FB3D995EBE57056240AE9FB87E3EA7868E52B9C6C98", - "ldt_key": "CC05778C76198E180288195C60A09E3097BF4179D28014AA5F399DFABC66C7403999595D5A124B56E66669BA63817D8AD33E4BDF8A181E7BD8AEB5EC0A0630B8", - "hmac_key": "71F06F85C029FC1D0EFA2F14B25E667140390C22681888FA4BE6565BCE65C0EB", - "adv_salt": "5523", - "plaintext": "E96582B1A180B733FAFA085DE5D6F942E6E55E2D0F6E", - "ciphertext": "7DF18EE13B77E39AE5C29B4421F3A64B4E0805BB2C21", - "metadata_key_hmac": "0122170D72BC714EE10582C5EECE1DA65BFE6C4FF396256CB5C122152DDF9C7D" - }, - { - "key_seed": "D78D1699F639D9CDA4190E16841C1344AFBB635D46CA61FCAC4145C8C53697E8", - "ldt_key": "F950BC9C3E082799E7B2DA2130146AF309A4C5313B98659CEF81A206985FB06198AA034154D5E25FDA57237F522FA424D584837325FE0C66C06A80C6C8BAE57D", - "hmac_key": "AF5BBB5BF2D84C7E88102222A95F7FD566040EB6E1036A78A90DA3370123D4F5", - "adv_salt": "CE9C", - "plaintext": "AE6430E1C1C8525D7B926B8D93186DD4AB643B55BD3D01CC", - "ciphertext": "66A36F510CC0612AECC4864C98D42B5E9C304E0F3DE19AC9", - "metadata_key_hmac": "540488D963352D79575337773009746203AEA174E4DE49F0A33621872723A4A8" - }, - { - "key_seed": "DBAB86015D39692FFC8B6EE1862F9BD6D2C8B28E4DA10D0432D1C0BD624511CC", - "ldt_key": "796693310002DBE4379A3927AF6129489F49E76134175135BA497C6B3623D2A6A53520F53A3581404D234ABE4270921FDBC5C72048E0D55CB30022AA56E40992", - "hmac_key": "9B95D807EFD135149898E701C2370411B0BFDF652C1D693C9759B20755909A12", - "adv_salt": "20F6", - "plaintext": "C5D10471EC644F0BE0C928CB0CE6504719F3839795F0", - "ciphertext": "D81B09EA189F737EBB92978AB0CDA63655B4D21DF6A1", - "metadata_key_hmac": "9751840D980E9B91097AA8DEF58FAF4D90F3913479CC9E96614348A892E6DBA2" - }, - { - "key_seed": "20BA5C3A8BE93060918FBFE6CB2EF94B0F32ADDA922132930351580BDB1C7B2B", - "ldt_key": "FC7F8C9BC3B7D93DA88E0884C489C20A9BC51CAC2C195B3371A7F0995DA84AB9E528693F580A03F8F18F2DD18FDE0287A6B129AD695D9A2CB6631A4C85F6725C", - "hmac_key": "0FDFB5FA8B335DED4681FF8E7D232BCE07199A19F2CEE581A388F09C7065C909", - "adv_salt": "347D", - "plaintext": "8636C156B78738A6474D89AE036CC3BAD7B2EA7D6A1C0918AECD2E2AF5", - "ciphertext": "BEE77F1FA9DBCF3773B0B803BF2822AFA4EEABF610ADAFE4F69604BDBF", - "metadata_key_hmac": "45362CD8C05D6C4A0AAF9B7A0D4D9E9B7F268D56EE1CB9067BA06751F414555E" - }, - { - "key_seed": "E1CABE143B819DDAF780F10E8DCB34557A110FCB16CA9C1208A9941139BC461C", - "ldt_key": "BF2AFAAFBCF85CF13761CD4EA9768DF5932A888EFD7710E5DE11475D2A59E377FD1E86248FAC144640BC8609FA105A64325FF7B586065E10BEF1A12EA839251D", - "hmac_key": "43C7D0D13D5A0665CA049A455DDAA10099FB9E0E0DF94EC9385D187254623F62", - "adv_salt": "941E", - "plaintext": "24CF3DB619D7E3BB10569664E2B2AAC98D7027", - "ciphertext": "FBD875C04016599BF12B11DAA4EB84B538F824", - "metadata_key_hmac": "147E5C30280A34487DBF757127CF1B38388A8D18D548E4EF9ACC86B8CC81239B" - }, - { - "key_seed": "19AE5D5D8287F089DD52E258C4E144B6946DD1C96D0365DF2756088BE98AB4EE", - "ldt_key": "794AD4D1E28308C607A4C05DFB118477DF439D002CBC7CD0D934F0999E922C4D00911B9E6E811CE781EB95878D5CC25E15A503150D84AA701F2A6127F9480FAE", - "hmac_key": "FD43AEAA7EA6A89D6A70E70169CE79C7790DCA6182609158D1A28E0E57744B2A", - "adv_salt": "41C3", - "plaintext": "315536736F3F2410448D02ACBFB5344E03E736B6B3AFF7C2", - "ciphertext": "B0440FB32EFC893AC3285AFA470A682BD45A7AAE268B20D5", - "metadata_key_hmac": "3F9AAE9B5918C539C94D9248FA88216562C0387B20946E85C167E758C07A65E8" - }, - { - "key_seed": "93CB8D5F88106CDFA7266973D06E3374948F29F19EE867AB45618375EFA7F742", - "ldt_key": "FEECCB7CECB48FFCDD0D3D4790BE89A62A91075A163A6F1B7B49466CB35AE6B609477E9BF1A4D31490FCF05DD943A0AFB43BEA1544B34BB44DFB0186C16D7069", - "hmac_key": "6CECD33DDF47CE8D66262B62EA863F797F6C94913EC9D9554819A50B747B8EF5", - "adv_salt": "68DB", - "plaintext": "3DDD2DB717B7BE43A4A951C4E324D0EDAFE15EA6A22AAFC96C5ED2B8", - "ciphertext": "D0E16957DFEA62294CF7BDBBE2C05F84AE95FD83A9CECCAABCB2BBD4", - "metadata_key_hmac": "52AA5B97F04C146E774BD92B35486C348A862F4D56535BC5EA3162FD6E8BC740" - }, - { - "key_seed": "B7CA1070E8A3BD952F7BE104D91A2C20F1D4796491DA3783264D50F6102395DC", - "ldt_key": "FE724B6F0520D7C3472AAA8F6BAB9B10BF640F8B63A6684829619C1A0AA756DA372F638696656BC72517D5236118C089E19550BBB24A3686A8BAD9EC141CA471", - "hmac_key": "9160364CC294664D46E19DE48143060DBCB5146A1F73287AB9491C2ED2A452AA", - "adv_salt": "360A", - "plaintext": "3C79AB767CAF65DC785FAAAC1FB38234A96DE51ABCD1676F5A09", - "ciphertext": "86084B5E0879225A3E37A306ACC94466E7CB29E83585514D08ED", - "metadata_key_hmac": "E98060247E9EB1B20EE37884C2BC30605927D75272AABCF543A728F0E31AE0ED" - }, - { - "key_seed": "D646BCB4030742672C4DA69C33CCBE4CDDFFE6F7483D784887775C3E265F4455", - "ldt_key": "E0E59C6E1A3C0744C9E2C1B3EE23F04CBF1D858A53F933298F401506C5780D1AAA4874889137DAA63E53791785F64CEBA791C4BED505F86B039DCC533D8C1133", - "hmac_key": "7934811F8EA0F86509A008C524D2F824170A380A1C254B5F9411CC1524C4FC64", - "adv_salt": "4370", - "plaintext": "6D6AE7D53207545ACB68BF4821A8A3CF", - "ciphertext": "1A04AB81A47C7B24A17C8285197D9753", - "metadata_key_hmac": "57E703B5F1867619BDA051C9CC319F6EC7A9BC7FA9ADA0FB9BA495ABD0C5C62D" - }, - { - "key_seed": "EA933E50C4F55A849B72E75DF0D0ED749E1BE736B7D17EB3F473C5D2FF8554D2", - "ldt_key": "63678EF10FA39BBEA18869759D3AE0CCC622DE4020BA28435072EF06B87F7B64B563369578741C7A7F0F867979EE5BA3B826FC5C2D4D7C3C53C2F006EE2BEF1B", - "hmac_key": "A57BB05DC2A606DF280DDE9F0C1BA63EC656BBC1C4D19BD25F0088B7E1AF7FC1", - "adv_salt": "6E21", - "plaintext": "3EFB804E7034A3D0B66E1E1A393E56DAB40700194C6443302486AD46DA", - "ciphertext": "BCAF0F9355A703378CDD60C269E13D2AA533AB6FD9CA7EE4188E58948D", - "metadata_key_hmac": "4639232C62E7507052B441900E23C8658CA36CF8630FF7C475275D169A187D64" - }, - { - "key_seed": "FD29F3B6EFE434E7211AE135BCFB24CB4731D3C9AF5A55BB40B097AFF8F190DC", - "ldt_key": "4425DB4BF28AE5BF322D6493D0375532E54518F1A503A18D51F8D95DC72F554D8C0204486796210844002147E67F3F999CCB4B58BB571A7D53169F9C4A5E4833", - "hmac_key": "D2B8B7B5B2438D8ED08B353A68F1CA27B5EEB8A6911C143462669E478F9B680C", - "adv_salt": "65D2", - "plaintext": "612405FB954646B9323C76E75463A6F5544905D16B84E01522F4201FDC18", - "ciphertext": "F9F16E4FA6202A2CDAC267D6D93FEF1DBCB6BB1C0E9B7C0A6F41AE1C9399", - "metadata_key_hmac": "A8D924AA9E363E0B272599CA171866B521BEC333E7BF1EB3C67C2602347D52C2" - }, - { - "key_seed": "CB46C2066E6C3FE16D1E8FEE5A0562E270F1783EFCF28D7EC8D77F53DCD0EDE3", - "ldt_key": "C5A1D7F25C2A6EDF97DC26D4052239AEBFA3A08B972F4DFE6A0A7122532D8785E0C96895E8ADB0FA61A02A4D967660EF7E4DBB635711118E3511F3D8D697DF41", - "hmac_key": "1D9C6580305F3669EAF24EA5A09D90A72C3F3AB9021A8D5426BF2CE50BAAB274", - "adv_salt": "D18E", - "plaintext": "3E74ACCD8A88A20FEA62EC733ED66A0ADF5268FBFC36D794D1A1DE4D", - "ciphertext": "52433BE7AD16FA9CB74F12E69BB34124BAEE9517458A6442E09D5752", - "metadata_key_hmac": "3316BF15CC1E4CDDD5EC092A88EF8154A6F43E725E71DC6ECB4A4CD27D98F678" - }, - { - "key_seed": "D0AE77D632C989982994F49442A58EF470A5BC5C526D38A3CFEFD94F9D160687", - "ldt_key": "F378CBE4511806A8F0C519624DC553344BEDBBF61A474135B77BB9760F964C9DC33D63012A45D4A32F95979AAEA481A44C3F49D53DFAAE3849564F1AFC89FDC6", - "hmac_key": "B078A96B7F1A4D5134B97C4BF3D436835F97A213C8BEA22D25BC5E4D16B78FF4", - "adv_salt": "D68C", - "plaintext": "6350114B94F70699EED4692575378BC0849CA57F8E30C3A1F4DB185D", - "ciphertext": "54A9DD1E2C1314B9726F5A440F0A1C6361C479050138A687FE10893E", - "metadata_key_hmac": "0BB547D578F7239770769E46E894D3EE3913D4BD819AE9DD21FE40C64473E9B0" - }, - { - "key_seed": "A65751FBC4AF24E2B9792263F001E304724EB37502F387F2EAA6A064DD7562EF", - "ldt_key": "A4F7E615D946BBE528FACBA0C2745BDCBBCD0A16B46F060A555E09AD48311049EDCAFECF1E1F5D8D126B59F18E328C4E49D2056A4BF207B5DD8CB195FAA441C9", - "hmac_key": "D5D089E402662DD1BA5592D0BBACB1996402B940E80D7504C5D6255A9A726BD4", - "adv_salt": "C61C", - "plaintext": "B4D35A9043A4C2F033731640321E6B7D1F66B39DD0177A4A0874", - "ciphertext": "B9D9F57EE1F23EB4B73EC949EA9EF5A51A3518F95D8917ABEA46", - "metadata_key_hmac": "B464EED3A47C4C83F1DF9271268C212B8528BAB1786C5F19E5EA0F4CCE9843C8" - }, - { - "key_seed": "DC35AA8B956AB62C7369FE1421C6C1DCF8D4A89D5F4062770DBC2BC7DCB8A182", - "ldt_key": "98233C8B7F8AED0C76E1284EC42D7723A09D741E2547B23483C334CA7E264CD068EFAAB36345D28605A180959F5338C543E8CCA9B355CB8434957B102684831D", - "hmac_key": "909F9BE62D6A59D87216426BABE9AF57C7160356C9885989D1A42D02181B2404", - "adv_salt": "5558", - "plaintext": "AC1EF76E499D137EC9F3191E9840CAA5BE5F317F", - "ciphertext": "7C966901C5F317F736D64FC2A43E66EB5C49556A", - "metadata_key_hmac": "C8E966D170968D075D59803E71933C049211876D1342B8F77F3F6FCCE9FD972C" - }, - { - "key_seed": "FCF4779A7A385AC0293B1B34D62755CEF4C5E88976E1A8840B3DA7D61A27D2DF", - "ldt_key": "DCB2889329666B6AFE271AF8EA534F360DB5D59A670C567B87810FA0B9FEEED9BBFE453B2D70AF34B8CA71609A0B58E91B9C3D9FA4EFB4749C236DBEEE50C0EF", - "hmac_key": "F6BDD41995C84BBA81C75B1C3996577523E671916B0943B89424370D2EC4D29E", - "adv_salt": "4E73", - "plaintext": "F6AA556C2F71E94D3F3DBC5AD7D1E2C27732797F", - "ciphertext": "D8D3F3A5B4589D0E034F2710A81E81610EB091D1", - "metadata_key_hmac": "DC3CA9D9424CC5CBE87972D1CE69BDFA77DA387CFD7158E07AA298CF245E2F3C" - }, - { - "key_seed": "F66DF6536DC842DCB7213E4B2D3BC65E7F339C44678B3065B84BEEE6875AD04B", - "ldt_key": "15EDB42867D0B6E7BC3C46D3222EDBE502B9E720ADA1723BD1868D16BBD12CBEBDDD95CD9B9E2C840BE95FAAD953F538C36A698254AFFF92B3E067DFD3545B03", - "hmac_key": "179E7E7E3040AA184323F846E19E829DDB11DD6B47637BF49783150294826835", - "adv_salt": "F75C", - "plaintext": "277603CAE5EFBA74E8521303A0CE661F34F344C4C0B1439EDC", - "ciphertext": "9A5A44DB5332510C1B9A0B1311C052578A0AB5C4951AB472AC", - "metadata_key_hmac": "4CBDD38306BBA9056CBEC40715E52C2CC83EB76AE733E371206134A45145801E" - }, - { - "key_seed": "FE1F1EAA8A3BBA8B446651897DFBA2005E2D8933DDE70E661D8958F858B1BE34", - "ldt_key": "E9D189401214FD24087347E714F91542FAB76A65A40C4584A21CE923F5755CF6F7EA5554C2CBD3BE29BF550171604D2E0D56B6FE2CE37C726B566E60D4888C39", - "hmac_key": "31A53453352877B96BB2124125315E6E0035522C2F44AA6FF1314D0EBC8F6615", - "adv_salt": "DDB3", - "plaintext": "0BFA0BD8D9D852DA66D1FA719B48E55EB333E05C77516CE2", - "ciphertext": "031274D8E91C52956C573E02F8ABBF7B581788D77246A66B", - "metadata_key_hmac": "A6DE740A9769FCDC59EE09FE542FB9DCF30B679BCF1E56499869AC1F8D71B837" - }, - { - "key_seed": "A41B8237B5EFA85322C6B295F9A0FD01F573C66F51D11C559713638860FADA27", - "ldt_key": "9B7284B6D26A35D1823BF0CACC1761E9C7B77536142083ED2BAD82D7B7F90D3F2EDDA9755A4C7D94CA912FAAD3023B25A226361A6F6D807B68D21D2E3F172D95", - "hmac_key": "210AA4A83DAA8F44AAB45C2CF45C642FC941FF8F9671F031B71B304C2EE64352", - "adv_salt": "BFFE", - "plaintext": "17FECC5D1CA89D84B293DFACC18AF52620691B2073576EF20F64718D9F", - "ciphertext": "D897733DD7C03D8EAC294656243B333682AEA9EB9B9D4724DA96D95C7E", - "metadata_key_hmac": "B7EA46EA057FBF194C154D2A7119826BEFDB6966B10B2B8F11EBF25873265BA4" - }, - { - "key_seed": "F21553FFD8917B76CF1A1E0C1812D5057B5BB37A420405BB13D61AF0D5DB0425", - "ldt_key": "89ED1A2E28EB0BABEF410471BCF76040F0837A54077C21BA1A818C5760C3B21E2983A3A433F36CABE5A35B32864E1CFD95871E5A2394EDD304A86414B5042209", - "hmac_key": "61A2C6FB83B556097116033B799DBB18FAF0AD9B258886B53089F7330EB49759", - "adv_salt": "4D4E", - "plaintext": "889397B6AC893582C8C35A266485DE160D1E68", - "ciphertext": "5B5297F79DB633F8A39006CA8A3236B4C19755", - "metadata_key_hmac": "EB33589BFB99F02DECFFCBF51DEEEBF44473831E9A5EB9BD4120E97944FFB85C" - }, - { - "key_seed": "33576D6CDC4B4DDAD12F5B0F5E3128DB8F521FC4489F8035BF9183A40DB97D97", - "ldt_key": "64BC452BABF0E22A22A6D2BEA939FF1905408A62E2B2D4311CC2EA5BEE606620FC56AE1A72007E815985C1EC11D5867F2734728AEA3E7117596AD50274066224", - "hmac_key": "8CF9B706F42010EF66E436D4F52CF07CB27CC39B9F64FF908DBC54BE3715ADCA", - "adv_salt": "9F30", - "plaintext": "F979E2241D6DCE47148EE498B74915D3CF3CDB87", - "ciphertext": "97D6DE5213BF3F18730B4A416F1F5CA8A82F7922", - "metadata_key_hmac": "C5169086AC1732F10BCE0171F0E6B6123F2694B9A54BB877350F0C5FB26A481D" - }, - { - "key_seed": "44455F60F506EE74FAF74E8DA03DBA97306DB0E54435E90DFB5417BC4AA48567", - "ldt_key": "A6FBF80E245F9FEBD5B33A69BC6F7DC5FB376882679F24C8E684BAAE86176921284B46C61A5CAFCC04E30BEBD4AFD88ADF41996F967E0AECCE79E3C81BED5867", - "hmac_key": "7F4AB7EAB331023CBDEE664A8C1427F7456D9B51D0D117D676A349F4E23FB33F", - "adv_salt": "B80B", - "plaintext": "13A2BDF201101D16B2DD1F67F8289BCB578AB83986C830B9", - "ciphertext": "CC7DCA27606BC196908DB7829D8569038A4160E5C703D5E7", - "metadata_key_hmac": "8E3B70B3C84F19A0FE164A78CFDF50ED4B49ECB053B1E7B41A8E3C3137748AEE" - }, - { - "key_seed": "620F0497C2E7C0923E7027DB0950298C44279CE4462C9A9FFC4EB5C0C6F24E74", - "ldt_key": "FFE023195807235A48D2570021C73BC9C7AE961B7DFDA117EC4DE62FD6CE1CD184504B465CD06FC9684DB580590F778BCB6A856FE3DA1D000EC53BB0E93DC6BE", - "hmac_key": "F13668CBA73DC4606600C72FD40D0286A9DE8802DE566BB66712D393F4BB76FE", - "adv_salt": "5DA9", - "plaintext": "ACAEC0B0773EEA127EFDACAB13904A4CB23557936CDF", - "ciphertext": "FEC2B147A8EF9D8D72205DAA62B3551504D0E5E06EB5", - "metadata_key_hmac": "14303ADB2D45E088A0BC2A96E9FCE4FA01B6DE35E1B494BF402B93805A6BF620" - }, - { - "key_seed": "1D5A56B6B5D8219556A5C5DD55EEA7C56E7A914960573963E78B7E36F8B49100", - "ldt_key": "CE0A78499619B86F9B0BC17D223A1B531837AAF1AFFF3650DEBA84C752FAE2656F690917688AA28B70E818022161E917726A439A39E52A97E4B6E097406993A6", - "hmac_key": "7056E12E07CD3F8A51A93D6E5A1A9A2907082A394CA39432B905DA0B48437C95", - "adv_salt": "3651", - "plaintext": "E416F4C78BB5FCB7761368B082E5E2395E3D85", - "ciphertext": "48A4172F05FB1FC537151EE4A1EE7F7F37B42E", - "metadata_key_hmac": "3E22CD89BF2D694F402A66D6799A087A03751A4E8AD3327B0EEE4E76E8C34BD9" - }, - { - "key_seed": "343596F917C924E089066303E58CF2FBE4CA7B4293AB79A71EDC6026886BED5D", - "ldt_key": "A5A59E049A67C60802D0345E08BDE961601576B830F1178BA15B03F9DABA5A0019A25A5B146735FED83F4E9D3C01007D252F103B5C674D3307800094A6B6A3A3", - "hmac_key": "3CB01FD40F194BD832D4F28620FB529EB142C1F51BB88241CF2549B41E192ED0", - "adv_salt": "30F8", - "plaintext": "774A7ED68BF415F37C54EF0061A5EB9206DF10DE14A8418E2B2D7DC8719681", - "ciphertext": "DB8830CA6DF1F4BA6DC6718596A437F748D13A7494EAB1E7BC639562EEEBF8", - "metadata_key_hmac": "2C791696B7948BDA85EDC4F97D983709A349CB9FC8AF2ED45987908D06AA064B" - }, - { - "key_seed": "338F7F5FE5DE001FCB7A5FF0D2A70DE2A3B3A3F7B41A4BBD8D73F87C2E73AB3A", - "ldt_key": "277B661A492F908F7EB506DA5E785FB3D422F484B6A7DF2646525774D5C766590F5F5E6DA8F7216A15173DD91CD81A0970B0C49B0DF5339AA44B24AD94D3C0AC", - "hmac_key": "691572560BB82F332962CFFA08E371EA0EA88F628883FA1A39332A5523093663", - "adv_salt": "78E8", - "plaintext": "D31824E9D4E9A438B561CEE0DABAC3500489C8EC01115A", - "ciphertext": "15634D0F2FE02F4DDAB92CCCE4C0F3C6941A99141EDE38", - "metadata_key_hmac": "8B6C181D751E8701ECEC1F37857BB77C4AA4A0DCE7751D9CA42F0E94AE4BB3CB" - }, - { - "key_seed": "F84F90B1D13F2A09D13EEE467A2B9CE7CEB236962791FF106A9539E967CEB625", - "ldt_key": "1FE83F9813CF84AFEC67435B638815704799E4098EF7588FD4B0E14D9898256A1FEC424ED650BFBC0BA99C4604462450527DD46787A525A6213E41969F0945BF", - "hmac_key": "55330CA8832B36F9B17CC2BBBBFEADFBD78A4BCDD2D9778B31CB79CCA690AE5A", - "adv_salt": "BB5A", - "plaintext": "E828F91058D295E6BF37115766CE369F199897C6E2", - "ciphertext": "DB181452D79A03D1A31F94C3546917B494D88CD216", - "metadata_key_hmac": "719935E3EB1C9DA6C9235EC8A0091BE8FAD0486AC081C96C7A31E435E145AF8E" - }, - { - "key_seed": "D289D134C02CDB24C28BE243556A71DF5718818A827780987FFEE928A7D5D1A7", - "ldt_key": "1DB0FE1F97D7AB111652C98B580F48F134B71B967B0E68D00CBA3EA5DF7EE0530C9C127A064847816757903145D99A5074EDD3C18144AA156958799FB11C517C", - "hmac_key": "8E61F0963EFEE787B02CE1C3A0E86015AA0D5CCC435310E6AD14BF1829E5AEF2", - "adv_salt": "6E0A", - "plaintext": "E87954CBCACFF97CE4CE2FA5F8384DA6AA2DD81A", - "ciphertext": "C8802475CF6EA2EA71F2A7C83313E3EE549A2CAA", - "metadata_key_hmac": "DFE63756EA5C4E9FF97A61ADDC0CFF0E07E9FC149F6274B80142155B614C2CC8" - }, - { - "key_seed": "63A44B4A2D3E81D00195D1C006986E0330ECBDFC05D3CA70530B8EF99137C860", - "ldt_key": "7F88032C2CBBCCC894198ED3759E126B7809CB39F5116AFD63E3B4B83FAECB94B7D4688B25F73A6086E60BA550AD8053CCC70769BCAEDF1AB7CA112F46DA451F", - "hmac_key": "CD4875290560D8E8F54E972627CD77F63240CDA9D495AD74B93D117AAE33C127", - "adv_salt": "4C93", - "plaintext": "459A3EB639253EFAB1F14F7B24EC036732D0994521", - "ciphertext": "F10BACA9AD20E9525499E79ACD51B0B0CDF59C2D89", - "metadata_key_hmac": "44B771C56CA3CB5187D712AB8B033B049F7239A5D38EAB40F1F8E1CA066C7B20" - }, - { - "key_seed": "0671E87D03B5207B3970DC43EB05C6E38D86BB9841010369529E2092C364C668", - "ldt_key": "7216ED7C5FB156A854E4243A84408F34D1E9368C9399240E8E7739AE1AEBA335790BD2DE3D2B8D29627D1264C3729EB365B8540D447D1BD46C4078CF244E8B99", - "hmac_key": "8B35F9DA6FA6DD84B646FFA132ED4A0380C9AB31A0504BAB483D6D1A96AFA42B", - "adv_salt": "6F62", - "plaintext": "CE6467A5DE9BECEC553CFCB1FBC314A5ECDB93ABA5", - "ciphertext": "A63ADD1C0C87D2D81424397E0FA7AEDC2520EE8142", - "metadata_key_hmac": "6AFC2447C731FADA03531F1289A776F2FFCBB238F6A35D238ABFEC74B6E14F05" - }, - { - "key_seed": "06E1781EDD38E90809FCB33CE7CC689EBBAE0C68C6FC66D58D3D7D4ED23CDF9E", - "ldt_key": "CE2282288488EFFCC70EA72BB5942392433BD99F26B62A2CC7B98BF1685CBFB4B386D548007CDD3A071F2FA90944E59282B0D7D8744FD7F050CCDC2A789A3130", - "hmac_key": "82024C7FA981ABC82F4E59C1DF298DCB82DCF2676E8D05B26C14078B7AADF06C", - "adv_salt": "A351", - "plaintext": "CB9440C3CEF90BB45C89F16A8B33478775B3C2435D", - "ciphertext": "CA2B2069C89B7C4F24E5A9BFB5E91D02139FF188B3", - "metadata_key_hmac": "08D9897B9E08AD1FEE910AA11F91EF1035CEB8232B7CAA00A5D55A27E1500827" - }, - { - "key_seed": "0C0C617B25804C4D513BABC7A4506CD66107181187213D6A9F229C13EE9B7055", - "ldt_key": "F36A44BBFB40B88A43C039FC994EF3011946D120CE95D214DB65858664FFEF3684C5D42688E85610F02DFF9A4541F5ACBB10F8FDD537BED40905F5586A4D4AB9", - "hmac_key": "1128F3C5F11E7E06B2812C3435DB3C6EBAA59CA91BAE4388DA10781E30A35AC9", - "adv_salt": "6138", - "plaintext": "04812107FCC326D0BC12C6A6F76C422C38", - "ciphertext": "EBC81562653E5B8E86CE2B66EC69FC88DE", - "metadata_key_hmac": "0561137A058B8DC63E13135E8A4F39CBA552C43245904CA500035369E7A7E7B1" - }, - { - "key_seed": "4F5E4D56119949738BDB7DBDF8158494BC073A949BD78075AC84859446F0818C", - "ldt_key": "0371A5EC3C37174F96E063D948EA8C3AE6566DE2224DAB31494D24AF1DA81429B4CDBB9F90BC181052FACA6ED3FB594DC0D53497A8B550F8651F28DDCF8B5F83", - "hmac_key": "D8251CCC9C4DA0E6B31B22D5ACAA460175F4B8DDC52A8346B7D6D3BDDB9E7937", - "adv_salt": "78D7", - "plaintext": "C211D8FBDB541B6851BCA8738635696FFDBC3B50D449C4B961A6703E", - "ciphertext": "0B30410B1E7885E84BB5F1FF61A397D4A92EACD49770F6A44DA70370", - "metadata_key_hmac": "4290CEBEE66DE312DA9974ACFADEBE7587207D5F9F893F2DC33C6FA50BF600DC" - }, - { - "key_seed": "0B3D2F948D597CDB11ADFC802E1DBA6827E0CCC4D6649CC459B1DB7C6CF976BB", - "ldt_key": "A520D05C8D03859B4DC4218BF7E61F86CF5B4116CC959833ED158F64B4199F5E85BB8AE4FB72F8E18F67F991A7555D264F7D109157E7CA089489857C481C969D", - "hmac_key": "831161162D181BB9D02877D4C8F048376B33EF281F7C2D3C57409106F68FA3BF", - "adv_salt": "EDBD", - "plaintext": "A78301B95D56985B6A81A69340E10AE872125BF8F76898E7", - "ciphertext": "FE052157D4AFA6B46B19CA1EBF1CD1F500A844BC8C165530", - "metadata_key_hmac": "021272FD20767E16F0222DBBA83562579F3F8A7A9A6B86D41C79C188D0F43086" - }, - { - "key_seed": "1AC2CE1A2FA2564AB3A0002858EA9E27D6341B5CC64FD22DA6C6AA07326D4E47", - "ldt_key": "81DC06F871C1A1C60B9907F55D95582E7E48B82DA79C3006A9F2BC633976DB58B98121EF1E0E1CF82A78BFFB30FF80127542E90114AEB9955B908957B5F1A382", - "hmac_key": "761B180FCF4DF2479C797EAAE1836FDDA1B173BBBEA7129E0F2A8C4B812476A5", - "adv_salt": "3383", - "plaintext": "ADD5480A412C9377957B9B515B3AF735F5C18CA3", - "ciphertext": "67ACC73A744516A9FBF7BFBACB98CECFEEE00ECB", - "metadata_key_hmac": "562C4505EE7EFC1AEC79474AE31BFA9CCED521CA5CCE16039E8A259010ADB007" - }, - { - "key_seed": "D158900DDFB6C7198932B9E90ED920ED579E61657CBD6FCA17AF281FD4391F6F", - "ldt_key": "C5D84CD86F7017CB8147BA271AF2FB950D15CAFB36AECBE9FC7C51B1B32593DBD51503FD5C65F9E6E469FA2F4446FFF3262C049CCD0551B68D730C358F725E56", - "hmac_key": "73F15E0895BBA3EF37191484FCA3D885A71566652E9E3BF6D81F19C493659BBE", - "adv_salt": "6875", - "plaintext": "E258A1888314766D42C8C0D3DE4024BF8F79", - "ciphertext": "61B327579A311B0284B9083639640049A4E8", - "metadata_key_hmac": "C445DEEE44EE21B8F567BF2367A3FC1956FB0F1106DEB7E05C50135260CE40D6" - }, - { - "key_seed": "10A7EC5CC4EB65A498706ECB585F880F833E243757C7462FBE6819CA6771ADA7", - "ldt_key": "4DE3F63E1088B1FD84D5E86468FE11CC217756F1843E47D109C69C273FA0F59752E52B32AD57A73492AA7240B3F7DD934487FCFB3547DB1D8932373FD7F89EB6", - "hmac_key": "142FA8A07692490DBE1B9E4BE43A7025849FCF9E6653CD2318D743E4EB8F904A", - "adv_salt": "C61C", - "plaintext": "F417E53F7D6539C14D7F5F99FC440908FC6FE7E9168288456551967F5A", - "ciphertext": "D98725AA5980237FFF6975C31B40B07C4F9F12B89C30191EB404BF09C6", - "metadata_key_hmac": "F0867138E739CD593334B0704E493E33511070A60E071A94B441F4826E012182" - }, - { - "key_seed": "98D42129CD845E7F14843B9D9CCED882989BAA2BC9A67038F1132A567D58A91E", - "ldt_key": "C229D7C951FF00E05F670BDC877FC9703D1DA5C8D9DACA5611CB86A449D5A0714C54C7D7F9D8AF2BCC42B352D11EA1FB12107674208E972A38DB1B34ECB2B1B0", - "hmac_key": "040D8A7A9AC888C04E097AB62CBBC0F0E5D69692F20F186C837D91683067CEFC", - "adv_salt": "6755", - "plaintext": "0501C4D75F74EC2BFD9EE99473C2339E649461", - "ciphertext": "F6615A5B104736383A242938A9704E19E0B621", - "metadata_key_hmac": "445BBC855FE10FF5B2CAE5F6416B7A6D698930EB9008FC54B4FA06F58FB2BEE1" - }, - { - "key_seed": "78AFEDA040450B152F85D4510FC718A059D6CE23C0794109B9362125689DEC61", - "ldt_key": "3DC90A9717B472F082493CCE5760044401E6C0C32496863981112A9D1ADAEFDD79FD421CB11170CF12DC7F3EB7FB0B85018E8A32E7391D25773CC9DC88AFBE5A", - "hmac_key": "890C9AAC2820FF2720611ED90B7E3DC4663F07966005F56A6EA9D167CF965E0F", - "adv_salt": "B397", - "plaintext": "951FF0A7A682651DAFDF47C0E19E1E56955B3877984D5D842A84133B", - "ciphertext": "E4D79F17E817D3852E3F5E9FE41D020EFF984C39BB39AA7614664B2A", - "metadata_key_hmac": "791D3A04FF1B72A68E9229F4D7E6CE4E771B01759A07EA940AF17449C72FBFC3" - }, - { - "key_seed": "3AAF11C94241718B0879EB66ABECB032147CD05E423EB3B534BC4E747605468A", - "ldt_key": "757B05A0E86B9C0CF6BD13836C31BF66EB53C13A009E0C808EED2A0AE9AB6C55E580CC712DBD0A54C33CD8BDFD6F7BFC45580F49A68971A23B534F3A35638ADE", - "hmac_key": "9462EB8DE0A29A937A227AA1345501A687810E321E0C0E7ED98D6AA80484E9D0", - "adv_salt": "7ACC", - "plaintext": "E4B0DD617B62A9F2F4367ECE4D70CAC7E11E5FE5CC3ED12083E9F4", - "ciphertext": "B43DEA72A65B4C0D8E5F815F4F1F8AD56E1FF69DBF53CB7565F1C9", - "metadata_key_hmac": "ABA6B185C97738E69AA2D439AAB09F111F9AD0B6625D8D9079873F9E5F1011E4" - }, - { - "key_seed": "1254B4969EE1573866EF96A4DFD1CC7CC50086AA06567279ED31E753A7512FF8", - "ldt_key": "0B0F718654A1B737BDA6696B4D7E0E8F34E80A5492539A0D69461928E8FA6E0147C3139BB9D2EBD40E6BC24631EDB713332F83354B7C5EB585B15E2A31539603", - "hmac_key": "331571E071186C989950281590C97134B0665B379E67BA173945CDC657EC8B54", - "adv_salt": "3C44", - "plaintext": "F59080AB834F6E10D2F9C2CE3FCA3FBFAB35", - "ciphertext": "52EB13D24215021A96CA404C7DBEBF1285B6", - "metadata_key_hmac": "245D7F20A26FA4A49A92C9E8ABD9BCA76639817BB2DE8DF660228C3129312578" - }, - { - "key_seed": "A09389BB1599359C1A54F852632749B2AE314FC097C91FE44B1667E66070543E", - "ldt_key": "04548B847DFBFEBE23CE95E67407F5BC30AA6BE449E75499FCA5939A1FAF68EF8B495F65A6E043A146A4737C4F2C95B286B2E3AFE5A12EB78D9B9B6E58E729B4", - "hmac_key": "0E52834761585DF6EF60F873232D74D72EBA8EB198BCE30B58FEFD63DFA7F758", - "adv_salt": "8D41", - "plaintext": "63D67EA2B4D8360069FC8935AB48C51703E018630B965022455810", - "ciphertext": "BFABDE39D3F06CEA3408E4CB6596700B3E649ADB1472B615C23800", - "metadata_key_hmac": "ADA13495722DB9288C7C082DE9D457E721E6722790590B7F5EEC53CA33807657" - }, - { - "key_seed": "CD9576EE16DA0AECD0BFD036353AA99F4F379E2F439230F38AE70E21A41E9822", - "ldt_key": "5FAD20FB31538ADA9C445FC4D441D372902C0E1A84F589B728153AF13C19364F3F8B593FE6C2EC50F6B4FACF08DAD3CCA85B4EF8BF6B73A35BB09F4F9D1F2A8B", - "hmac_key": "820F0F0B8B99D29BA6555703C39171A5CDF99EDFD1014289CF345EDFDD0FA8CC", - "adv_salt": "361B", - "plaintext": "8A4B3F4778C90DEA493EB2595393660C2A9A592D9635942FF0862D4E4FB0", - "ciphertext": "2CBC9C9F19C243B20CFDD57A09C277DF84E939F7ED2AB63642BE7B68D5BC", - "metadata_key_hmac": "F46A16718E7ADD5B1D72512F477D2CCA606E06588898524EBFE7E1B699DBA7F5" - }, - { - "key_seed": "5A8687465EEF1596E3780067B4583A7FC4C4F260CEE84AAA0BB5DD9293D6CA23", - "ldt_key": "16A5125C65E844C3610DE38CF2E233121E6DBA36B33D3093AC737D6CEFF59C4BF998830E8FD0C52763AC09E80CE91CD8B5DF977182EAD82FC02A3BF00582936A", - "hmac_key": "4AFAD4D6D875B1FD17EC0270AD720842BDDE4BE82DCE2AF4B8FEE608FB1E823B", - "adv_salt": "DC49", - "plaintext": "30EA802B38189A793EC9A0556C8120BDB323EA2AF3AA441C1B5BF3", - "ciphertext": "B7977567D79D5668792212E0F1C4C4337AB9B354A17442E424EC61", - "metadata_key_hmac": "8363FC0C8CF602B0F0880C305E5B6D59E056D9F4B62C523A0A892F6A652F8DA5" - }, - { - "key_seed": "1847DB43A3705D2EC3D22784612C77AF2C90E8C562FDCA4E1D0608D7FAF59044", - "ldt_key": "DCEFE1116D69A3A14EF00163297A61D9E5CFDD7DCBC57A918C5D34695D6BBDECBD5860126BE689FF17653F6A78D1BBCE50FC2452090D5680DD90B3EB8A168DFA", - "hmac_key": "4D2671B9F1CDC2688D2CAC6C713BD9B8D4BFAED2FA9C1C86CD0C1C89FFD07B0A", - "adv_salt": "6600", - "plaintext": "E0B7648B869F159FA32E7AFAA73B7FD2F8756B3773C0651DCBD9F0131555F1", - "ciphertext": "AB5944D92E32F9315CBACE0DEF010AC041228712636D06BA88573E189050A8", - "metadata_key_hmac": "1AC08918FDF79487DA33EA74523CDD0E31CA5D50657F75EB87BBCB5D44A51C18" - }, - { - "key_seed": "8FD04A9A906A7FB6747A682C0D86EFA3DC353148C038470AA201D009945428B0", - "ldt_key": "6ABD509CC4CFD4899479DA3FD50F948941E6681943AB9A7D4B348787215809A1B5F38DA19DB1ECA132AF464D550703A3F21FB5DC67925CECCCEBCBED8DCD4352", - "hmac_key": "59E7493AF6F7D9EC5A5A18B02DE1B69FA49BB4955D871FCB20D6B840E8E65FE7", - "adv_salt": "E344", - "plaintext": "FD465A3957F9186D57E9622CD6901A3B1CEEA86639BA01240186679C2160", - "ciphertext": "D198B506ED55D44CE3B2B06F564EB41577E4A21BA56A4581897AA41E41D1", - "metadata_key_hmac": "E17EBE7EA3E31442C9F77484B2412B93B21035A09D2CF2B7D302F5595B4C180E" - }, - { - "key_seed": "5D6901027D2CD532A9CCA83544CA250CE4FE48F6D2ED656D5F53E644693AF48C", - "ldt_key": "23C4450CAB72981CDEF0AF4DE884B96F2CF0410072278DDFE17076CCEEACDA62017F3C57087C30F3D135CF7A7BFC07310B6EAF35266C3713E324C1A4503C3962", - "hmac_key": "1F71218394C4A14E4E0DC8F35845618BCF661E43F7D94CD65649BFD7ED7F7058", - "adv_salt": "3FEC", - "plaintext": "055458BDB0922E3498E2D29BA1915BA2FD9E44BF0AF5E42ACF10D03263D42F", - "ciphertext": "63A18209632293B8FDCEBA574565385C14AA076082D46C1D5465553CA97191", - "metadata_key_hmac": "100E1E9585B0B63E231CC9CFEBAD3844F091F8B43B257984B807879BD84E036D" - }, - { - "key_seed": "EFE159ED6B66C394C457F074EA67F073BB21D9AE07CF83C160ED0C1A94F6C1AF", - "ldt_key": "CDF76D8FF8E3F9C6E978067C0F4C431B394897682721234DAD7080AA095118CE1C39BCDBDB326E015B58CFB152DA9EA5FE064654DB8CC66EEF2ECE21491F7D94", - "hmac_key": "3DE7A2AA19F99374C637DA91F16046168905BF370E9E359C8338D979D84AC736", - "adv_salt": "0633", - "plaintext": "7BE0CFB84C85FC14073BD06D8969CDEF193A6CC5B7E799", - "ciphertext": "B03C781FE475220B173AB01853493C8ADD344868399711", - "metadata_key_hmac": "C6D156F2D028C16472AA9EECF256DB57494DCAB97399F56F9EF30ED1809F994B" - }, - { - "key_seed": "A312E637DA32C34019ECF3417F6AAF45152A22EEA52E1B151616167C1B774F19", - "ldt_key": "9AB49588EBF4E929ACFDDFE2E8FC1AC12A7BC31AF2ABB44BF03B7070E19B32A39B41BF04F1CED0895F5FD3C7FD4BE5DA33B90AEA97EA0591C6798E56D4AE6332", - "hmac_key": "542269456FA4FF4D150008518B032F9C7D7864E907D88F367F85624C29BA1C4C", - "adv_salt": "4356", - "plaintext": "9D48B29E18CE314B8603581923ACC0228057", - "ciphertext": "F577503F99D7D42623A6064383DCAEC22AC4", - "metadata_key_hmac": "1A44E9E237457DC3D3A093EF67BB2B915A10F2A7A22386EF05B27FAF1005DBEB" - }, - { - "key_seed": "E8D47D10575C5D1E3630D342626BE5CE6812B2E5B671323CFF42FE76AD265F28", - "ldt_key": "32F9CC9C4712DAB732229F54E0F2286B1EE5E10E9A19EC266C73773C84E9E86AEFEBE870E255F24964190D8FE49E90DB238FDBBDE525F9F28D7838490778172C", - "hmac_key": "8415654B8B4205F056B2C189A280627EE5F908434495906809CC4D3C06046E24", - "adv_salt": "E5C3", - "plaintext": "F816AA6A681EBD851CE3BC4A56F93AA384132A42DCA7C04DF1731490C90B", - "ciphertext": "2DC2F095CEB06C6E3081EC159FE13E97EE667857C37A21789E8714948C8B", - "metadata_key_hmac": "E3E8881DFAA94F0F305D1F43374FC455C7BEDAD8B5BA797752FAE7BD08A14E3A" - }, - { - "key_seed": "4DF9A725DE24A1164A0627D2BE4BA6B8F3A77E47A635995A34089A5AEC6877B6", - "ldt_key": "3A582C64633FEEF62D3CB71D403835CDA34FC5D3B41DB2370AE9082A0146B1E2300AB9517356DF91AD544E70951C2F16C5E0FE06CC1702FFF6C9709232DCF569", - "hmac_key": "EDCC46D1F0A60F78E7F6EAF19B142A5AFE9F01C3F9A830CD2795D2246F93FF09", - "adv_salt": "F806", - "plaintext": "BC751733EB97C2E703EEF578FAEF3C437AFB4A434324DD1857", - "ciphertext": "4AC979B439952949FBA52435B0598AC3BCFFF7B07D33CDBE20", - "metadata_key_hmac": "21DF4EAABDC368D32D1AB8A0AFC56B6752CFDCF17A9DBBE4AF7C96C3BD7A6871" - }, - { - "key_seed": "01510C4FE0D9308543FDF8B5CD9A01C60A671A408F9D3E0F844799139A7C8DBE", - "ldt_key": "08E67910642AA0B2EE1610F9B5EB7061FF8C7F1A94C61261C3D9A558C5E736A79F14381001657B97236B98BDA66DE7D914DDA4C860AD0E03439601A27D77FB34", - "hmac_key": "0B94AB4C41BD67AE18A13963A62294197F17C6047FA8708DCD75900E26836CAC", - "adv_salt": "CD77", - "plaintext": "25278F8BD0FAEEBB70FD18F0A594F887C2CABF4A7A5533BF14E66042AE", - "ciphertext": "87008C6E8EBB8215749717DA1F266528E83AF6FFE1E938FDB9B10BAC25", - "metadata_key_hmac": "E14A9EF23DE4C90F7F3910B069A20549BFDF1E2FD351697C7488A0243FD04DAE" - }, - { - "key_seed": "03426AC28AB41BFB34BFC4395DB65D34CE1592C6637049BEBF285FCF6D4D752D", - "ldt_key": "F864AB194A8EEDAA86733A530CB239A2C6C11B1EB86F18A9F7340C52BFE1D5D3D479103DAA18A830718029961012FF2822572FB2A38661B9EDEEB5531F1E438C", - "hmac_key": "55F499D3D8EBEBA2D5849D86155D4EEA9010589013DD791109687EE09674539E", - "adv_salt": "34F3", - "plaintext": "D3DC2B17B56AF59D3CF9201681FBC37240E6", - "ciphertext": "320625C1CE2D1345E9A5988E837DB38E690B", - "metadata_key_hmac": "62F4232C63E05843ADF561D5FD72D3F9EB0F0A00AC94EAF67515271619F03C1B" - }, - { - "key_seed": "08C01D4D30CDDBB5201C54E1646702BA1FED8767C690D8C312EC05F961202393", - "ldt_key": "117ADD7CB116BB4AD7C1873E41E43BBE115F47F9A089EF5DFDDF1D30EDA4D7397A8D86DBE1C21E2245A79F9E91CDA68F5EFF8CE68C18DDEF808CC67061709B27", - "hmac_key": "4650BF6DC8969E8D8878ECA7559F54DF24B3A4980E45B10F2B40DF56E18374FA", - "adv_salt": "3438", - "plaintext": "3FA70D0FBBD749AD720DF7624F209E1985678AEA951A3C640C62215813A633", - "ciphertext": "A732659057D8FD106AED3EBF8DCE945D16D681FDE67574532AA55B8F020BDD", - "metadata_key_hmac": "2EBAEBFA7F0EBB889F269F00BBB08973D13C07D1C4BB233245272651BFEFCDFF" - }, - { - "key_seed": "294BDD21742BD87E8C031D4459C3C4D752A38893AAD3EA6589BD23D2572E6007", - "ldt_key": "FEF9E32525787F8E8D3F6823E924272F74E7A7DD9803324A553C2DB542FEFEFF828760512C5336ADAAC4B78708E8A7ECD5329430947D7172DC39B1FFFD173C50", - "hmac_key": "A72984997949D2A31D511BE11D857B39E983A58FF8D8CACF758D646CE1EA9D4B", - "adv_salt": "3893", - "plaintext": "E7C5D221E528F0A4076BE5F703B349804BD288A458B8B1FAB1D249", - "ciphertext": "41E4F42E2928990BC1AC8D5F286A6B841D9CBD0C46CB0DC8F4386F", - "metadata_key_hmac": "4D7718EA2A03065A867305D6D5608B295415953F7E051FE5BBC4CF386640AE3E" - }, - { - "key_seed": "BAD140BD7F5A746587950B769BEE2B86C001A2541DEAF6A8BE3BD89037624187", - "ldt_key": "618EEDD9A044D8FF3ADF7E749B7C0212A6B412B617FD9243C13CD4AB1817165CE9994745CC4AFA37DB98896FEB0068C18E126E9A36D6555BD33F5F409AE64C0D", - "hmac_key": "052BAB530B00EE214BB87D3A7A46470D373749AA78BAFEF1AD2A64B0C8728C94", - "adv_salt": "1CDF", - "plaintext": "74B1AB802BFE75EF1F1AC4FB8AF7DDC0741D6AB3140F4768", - "ciphertext": "F51E89A9AE7D347B2CC08174D12B2B07247A40098348D657", - "metadata_key_hmac": "AC6B3D12A30402663791B9CEA541823F99EAC95F21F2D495755FFDBA8F43A5D9" - }, - { - "key_seed": "AB936D1740465539A92961132253ABDE638C304135D1588F8157215CB291120A", - "ldt_key": "DB2DAEC702ED084B1FCA7D9F4FEB0F140F12B22F5C194BAF069E884296188D627E1C5C798C9F38F0AA9F9999FB95F6DA875CF49BD07AD9365F4D121C27873245", - "hmac_key": "0BB72516DE709C6403299B1800FFD09AA4B013A3948550654615BAE08A96CCAC", - "adv_salt": "737D", - "plaintext": "97BD94EC0E4C326BDB76403DAC23921D77", - "ciphertext": "2E5C007FB9E59BAA4A6A538D32B5E9246F", - "metadata_key_hmac": "48541FA93EEEFEBD8E36969957F326C1EBF9DA3232FD4288C144141D3F6876AF" - }, - { - "key_seed": "3E7487C215462E75514BAAA0C14A4DD71D6E2DA001A31BD8A3D9FE5C6D962195", - "ldt_key": "6D7359744B5D4082F100A636F1E6FBBD0329913360B9947114B623E84F2C221BCE4D6219803FDDF3FCEE9EBA44C4630B852715671543AB241F497B2CC8C53291", - "hmac_key": "CBD41B6071A3C06581C1B5B3EF442DDF6D1591674AC97A39695B27FE296FD389", - "adv_salt": "7FCD", - "plaintext": "E03882ECE4B6F113344658F383B03E441B57D33C9BA1E8146CBBA3", - "ciphertext": "221C55F242986552EBD1058327D0DEB7032654057212C386FEDDBC", - "metadata_key_hmac": "6CC53357EB70F5C56C1E856EE439F1583D41B7037FCB072B041E2682102E089A" - }, - { - "key_seed": "E9722D366DE0F0A0F7A11228E12434FEEC5A203EA4947555DDA1911A3EA0111B", - "ldt_key": "A8B8C662D022A5ADB541CFAC69088998CC8101DAB078DCE30FB2AA5E2DDC7CFFEFFA0FB331925044397FD0C2C6147C6FB21CFC0D64295D43000FDD7CF6B1EA40", - "hmac_key": "470953916FA2FA9EBB4DAEF62AA7ED658B03D25BFE529341F7B78204207CAE4D", - "adv_salt": "B39F", - "plaintext": "E918E8CC19B02D63DB53134FBD127C6255428B", - "ciphertext": "ED7299FFFA71919FD7B15DA880B83C3442A087", - "metadata_key_hmac": "A1D94715CEA145116325103C52F8A8D316FE51183BDBB132884B1F552320D96A" - }, - { - "key_seed": "657F721007F3A48224D51CABF73C85B9CBD0A2F029DFFE519634577AF244D28B", - "ldt_key": "D5DCEDF527E99FD41790C0F3DE8AE36FCE74B789AE79A90F72C9D842CBE36F895DB93B0B2196FEF8B199C1622C6CB24BB5CE19DB55A0AF1E481E0B0315C0A2A9", - "hmac_key": "F8A9D5E1C4B5AA2EA3841FEF56AC0C7B78E9D573B463EF8B073BF68304C144E5", - "adv_salt": "0FC4", - "plaintext": "B2DC5FE7537BF4D0EB7325E4835C65A8A35A4AD9F0AA933688D0DC83", - "ciphertext": "D6187B040563C6307420E3B13DE6994962EB52974C82120A015E8CA4", - "metadata_key_hmac": "7CF960B3272CDF434605907361BC2B50570AF1D6E055989F41C957A806339BB5" - }, - { - "key_seed": "292C5A123A43D0F42E90127B105318404DA371C996C4A17F5DD6C30FF7958406", - "ldt_key": "987A64406EDBBC011AE42F1A3D9DE509CA4EBF10143F3D5279F096E151C43A11BAF20B7580811345D49B9B9A5E5E2CD726D72C9B0BA5222E1E265CD5E1BF113A", - "hmac_key": "CF47390013455461037394AC76EC721743D13D853F3E9E44EF7B1D664B3AD5E9", - "adv_salt": "B9DA", - "plaintext": "525225673F0CC5E39A71CD89221DE13313BEA7", - "ciphertext": "06CA5248993A16EDB9B2B17043828FBBF10B44", - "metadata_key_hmac": "A3F213031DF32074A829B32C53CB7A518BCCB41A77FF2568083C992F457A727A" - }, - { - "key_seed": "63FC259C4DACC377FFA83C5338B5BB5F64CBADEBA56424668124DB5CBD0BDBFE", - "ldt_key": "FE993C17559AB863ABDA0768EC49C18C5465257D8F13DDC39FDEEBC35F3B4359C374C8A011ED0985FD61B7179C89E3E91A04BE61E936B311FD783B81C8D068BB", - "hmac_key": "63ACA66A9AB40DC5F040B85709DCCBB1F88841854F6738EA597F14A5D7EB0D0E", - "adv_salt": "4054", - "plaintext": "6A90C5445CB4D7F424B53CE0A5655C84B39BA050B00CC6", - "ciphertext": "AA64031B3260E182AE8B0DB2E98460586C913DAE30EBE2", - "metadata_key_hmac": "C192FE644E52388C10DB86D8149FE52A4612C3B735FE6E52BB1042DAFD589C1D" - }, - { - "key_seed": "A10EA2C864E46ABF4668DDF75213767674DF97C6556DDE65BEAB28329167A460", - "ldt_key": "326548F1A422A58F79E50DF5F0706115943029F567271583F6155FE2F3380674BE9EECDA0F5DF4817FFB17BF1F6D93B2CCCF61339D722326B3400540367DCE69", - "hmac_key": "9D34F06F4423EC5CA77EF649A9A1FD7BE435421AFCC624D23374D273E8DEE70B", - "adv_salt": "7356", - "plaintext": "0B6B2A17907494F0BD1929ABD84A0D63970A", - "ciphertext": "38F245C019AD4DDCEF3985E17B3AA6F5CC23", - "metadata_key_hmac": "C77ED847CF889ABAD73E5DE31D839E11F61B53D74DD830C522D7703DE9C935F6" - }, - { - "key_seed": "3A1128D12AE1D86EC7E38F7734D21A53DF90CAFC0F77D9E4FB9935531D8E092E", - "ldt_key": "85F796AD7EA67077E4F37DD1E6674095E2520F678EF3C66ABFBA4A934B071694FE101384B7293CB5E0DC9DDAB6140D15BD0556A369780E4EB78D9D5F899177B5", - "hmac_key": "BD3105688CD274A3D32733856360ADD3D0FDF9F8EE3A87AEC93361A0FF9C5BFD", - "adv_salt": "F5F6", - "plaintext": "BB91A063B68707B5EB408A9456FF0B70DAE42FB71D", - "ciphertext": "7EF28CC2CB0FB35502225B878B7ED0FD3964139FF6", - "metadata_key_hmac": "E81803DCAADCD2CF4594E3E70E1423F89BAE8ED72C225E9864F784E6E511E1DA" - }, - { - "key_seed": "99B92F70AC9546883FC032D413C7BA43251F5B1197157029158A273090AE4AF9", - "ldt_key": "081F9E2C943245B9A217B1317B077BB702C54AFEC867EDE7B69DFC4426A1F70F4AFB90DD095121CB41C3FF3DF39E7D74778DF51002651B9E7231FC47BBDE10A0", - "hmac_key": "2013269352BA181A1A8342DABA04615833B4EA47A1B7ED2E299CB4BFCD2C1C38", - "adv_salt": "7750", - "plaintext": "A9AA97C43D57268766AEE2E3B82CC3FE3F", - "ciphertext": "46CE4D6A84BD43EA523403CD81F7299E2B", - "metadata_key_hmac": "BC1AC137EA800966894058D6A4C1A3E68012A1B1D9AE67F035886E6E25A557E6" - }, - { - "key_seed": "D9B623A3217BC5B9CB0095102D02E35F06EB9386E3AE563F6011D1300A27F009", - "ldt_key": "48E04C7769AD29A2D9F6CC9172E73ECBD0D9B8C21F1CFDD34D261C8F06AFCE890E36F9CC9CB7E4BBAD6FCAC8A6CD4F09D366E4E3D7AE0D6BDE26F8D0CED7EFB3", - "hmac_key": "3A9009BAF19D54985BC734A2F8684EC06E043EC6B747138C3FF1B96C78C3482F", - "adv_salt": "69B8", - "plaintext": "DBA1FAA844FA6CF0CDAB8EFB15EA792CEC60", - "ciphertext": "6762F4041339250AC4228C15E2564067A7C7", - "metadata_key_hmac": "82D5B0A87195734D9492C38C51CE1FF8A7C957FC69402E2EDC7F88B8094312FF" - }, - { - "key_seed": "8540610609338C353920785A748CC82CE4BEA79838267C85E7A775B61EEC8268", - "ldt_key": "84E1F7A0A6B332F9E0F1540322B455C4C04A4E2346CD5F807A3A4A195F609440E33525F239E297F5768AAA589E78517C94EE9418EAC35FD51DBDE9B70866623B", - "hmac_key": "CA5EC32CB4FD314378C6BD4B101EA860674D00829E41D9F8388F064B894B90D9", - "adv_salt": "F555", - "plaintext": "F01F7ECB9DB990418271EAD6517B69D240F618291CA7E83A5E", - "ciphertext": "BCBD94D94F3A94E231419E5918131288D0E267806A8ED1C618", - "metadata_key_hmac": "7FAEF781D5087647F63CEF2161EE710F829CF9A6C3A3250F459BEA218921D4D6" - }, - { - "key_seed": "AE5859A3A592717E93B8718FD1356F25E1A37BE52EAFD8F19D5F01D72C8D5D01", - "ldt_key": "2A2496A1E26EF4AD9BBCBA362C6E76F6ECFAAE36411F8C1EFB75ACA61475E52FBC6109980CFC640F1D15E1A6DC3185D72129D802099E8A435995176B20C8DCBE", - "hmac_key": "5EFD065599480E3679211A8E9C6176CAE7ECF6464E80FDC9E69F484698F22856", - "adv_salt": "F258", - "plaintext": "DE7BA7D89F79FBA0F385E83EA06904401369432F116A52C65012", - "ciphertext": "8B338B47491186F3D6E22D54D9D170BA86C7726818D37B6ADB4D", - "metadata_key_hmac": "D9490422CE5E49F346A0DD3D0F747D7CE2136765D835FDCF36B3F535D76A3985" - }, - { - "key_seed": "92B9F22F44ECE464199FF2C3AAEDAFF3B7EBF1A25640216C4DC12701DAD31EA6", - "ldt_key": "33D565EEC55600910B9ACCC0D577CB676CE3B32172F6A4001B3E0D5FCD041B6368BD650193E3FA4BC012522B98B4ADE3F450AB6CB8DE6DC255B437CAA2039D9A", - "hmac_key": "47E3A833B777CBBD0435B64ACD5EBCD8180477E5865E23F7FB891FB9E9A4A9AD", - "adv_salt": "C9BA", - "plaintext": "62D57AE83E64A520E50F344F561DB4557331B60CC6F155E2", - "ciphertext": "6AFB293C8CD05172ECB9BFC1E8BC2D042E29EFAD51E32B82", - "metadata_key_hmac": "084E75DA1BF443CE36D659618F3169F76D105BF3EDD2D439CFE0D0066E3EF39D" - }, - { - "key_seed": "73DEED4CC7C9842A0DE8DACC70E8B4A556AAD079E19DCAD4F1A4EC0D844C4B9E", - "ldt_key": "86FCDF0D697B181D82FFF10DC9E1323A96A4DB937477D863AA23E29B1E4C01450C5585B70F91EFE9793DBCD88144212C3F8BD001AD70B8E526DDFBC5B4C7AB2E", - "hmac_key": "91B8956841DAC3C63EE9F0F1EDAB92B3337562E47E94B22EE9096EEBFB280ED0", - "adv_salt": "0399", - "plaintext": "C2940DD38E71C8AD0A2E03FFF6E36FBA", - "ciphertext": "A51BAC7F36F58AE6B17D4F029C6F7D14", - "metadata_key_hmac": "100599892D986891734D80390B9CBE2B65C7CC351BDB90C35B57065950A140B0" - }, - { - "key_seed": "D47D3EB118FC6310C7A9526DABCB0E4BA49588B357A98A8883142B23F0B47A3B", - "ldt_key": "E0176A395D1ECE82B324D23D7F2EDFFD563E36B488806E7F62F28EE11F19709DDF8E2D83AE184EF30C0551ABD99FF30DC2998B6637EE98F9DDF0824D20365719", - "hmac_key": "4C6C873F49F28AA342263ED3FCF9792815B4E08856AFF70BC4EB78E93AE950D9", - "adv_salt": "6350", - "plaintext": "B109D1014AE5F24A85D1DCEAD867672274EA7D6F6113C811696360", - "ciphertext": "3EAB6A7C151FA3D7FF92C2FDB036431CE042E8B4827C609CB60646", - "metadata_key_hmac": "1E0A2A08F07E766FEF889ACABA277D1241E5D745C903E56E97C6EAE449BD224A" - }, - { - "key_seed": "1B372B508A4B3F1F970F861193609B4EB3FD65C62A171A43731E9BB7BAA9F878", - "ldt_key": "B304027A3E70434D7152342FED8164365CB874FD0EA9D4D9DB8B0571F876F4FEBC9FC13C2884FD76C8B5F1DDF9FE6DE9D98060ACC1273889B38C54B018C8949C", - "hmac_key": "426D38B9AEDB2D80F2C4B3037E5E1BB5E676ABB286CCC1174C7A0135976C3C2D", - "adv_salt": "A926", - "plaintext": "EB7A7A86C2F103A2C960D1CDC0BB3704370A449D60C93E41A0C4D88C534E", - "ciphertext": "51679BE7B8F588BCA4F7E48F9B27C6F8E97AAFFE76BCB0CBFE4BF198D760", - "metadata_key_hmac": "0DA1E0F3DECB3D5440CEE3D0423C3580A0C1606F98DD6F3C3978499D1797C9F6" - }, - { - "key_seed": "754493F863A897595961A3764FD8BAD6E1E84E9FDA15246A47C4D133327B4C5F", - "ldt_key": "CDA99F0F898B4B266AE899861CEDBA5BD129EB23ADF3F177135E0FAE52B0010C209315C69A478B6B44140C0FC9BCF375EE292A9808C70FF49E87A2EA7DD6CBFD", - "hmac_key": "622E68EB5F4E2E992EB30EB45E3B35EF5E6DA45E529794501A272F0EDFA6E0AD", - "adv_salt": "A07C", - "plaintext": "F66887B63134A8B3E2C428F967FC28A40E2665187B9EC0F8B9", - "ciphertext": "B218E6D728D9DECB32790D32A5FFF66381A3BAA9F214D14F5F", - "metadata_key_hmac": "5D95EE76CCC49B67BBAB40F420D7A2ED2F59861FC2004674083BFAEE8EF09440" - }, - { - "key_seed": "A267D3FE83CBD62F70D1BEC104E66E1999C73FE878E1DCA48D532B15887ABFDF", - "ldt_key": "39871DC7FA5144E3D0861B152DC43E8893B4B4AF88014275BD7BB64EA92B299F160623FD0A4618EB22ADBFDC1F99FEB9C7F967290D6894FCE4DEFC7B243ADF1A", - "hmac_key": "C58AA858D6926937696EABAC03D17A1BB7D9E6ED80ADA6EA25F7657E6AED0794", - "adv_salt": "F942", - "plaintext": "4FBCF881713DCEA28BF500425DC5A8592AA03FF50E17", - "ciphertext": "FD7E72EAF67E73448A42BCE1E55136145FBD5AB6A6B1", - "metadata_key_hmac": "5B0F55FEFBB282687AB7BC04E51CDC5EAD2FDF944DAF9238CFD38A2519C51D59" - }, - { - "key_seed": "7590A9B827A09DD6BE252F2456F7700EA95BD03E3FBE909AC606AB6976EA5DBD", - "ldt_key": "8D9B9E904A63EDE22683DA49C27695D10B84CCED446D27D817F50E5CB1D2A708AFE98551E9CB92D9C452E7EB2393B2DDD0327D24AE46024D2DD68EAF5A321B5C", - "hmac_key": "91D3FE5D8A75F5A1EDD3D6DE51B8C0CAF0E6E579A6403C38C553F73710643AF3", - "adv_salt": "F8B1", - "plaintext": "54E53C14D0A4A72F6138A07CB9185C09B822A280", - "ciphertext": "64B55EB264C13E34ED9B0D296A3F85884C18162A", - "metadata_key_hmac": "33CD2E0D9FD1C0304E3EE973011B937EEEFA87C9C2BF2F138D18FEB1B5A54516" - }, - { - "key_seed": "89D2FD1C7D9BE6B6BC0EDBA1DB9C6C3F5E53BB141D22E0AF1FB2484D1E9DED73", - "ldt_key": "BDA29601D9DB432AFEFD93B67F3867C9AA31C7CE75362684D1E6029EAAB2F4DC48812293970CC287241F3571BE3E3FE391163A0A2989CEC271ED16AAEE45B07D", - "hmac_key": "0EC5E31F828B81589454F5D166242548AAB88BC252F5E3DDC283C667400ADD88", - "adv_salt": "89EE", - "plaintext": "89AD1A1A9D7FE6BD87BAE793FE161DA4004ED63DA608EC4EFD5E4F13955C17", - "ciphertext": "70167D50FB6DD67C974857C23FA09168F9F984B0C36F91066181E4247EE5FC", - "metadata_key_hmac": "292DB21E56B265F8DD3081DEFB8540906EC5C6276D16F2306D79B522A2692813" - }, - { - "key_seed": "FFECD4CBEF6576764BCEFCDC35D49F960F57C8EBBA3A7323E48359F045FD6C8B", - "ldt_key": "5CC1784EDEC21D04C34AEA949B3993BDBC007DD49BEBE6D21645B230500184E04E33CA0D098C5B51E3FFAFD18C95DFC70630D995DE874DD0E1BF09A8A15114D0", - "hmac_key": "66CB17DD1DD82408A7593463616D567B904107D2554D0750BF5AF527336A7545", - "adv_salt": "CF7B", - "plaintext": "F3FB937E5377F9DB4BD2D4EF2208165A6ABCE8641E349849F9503B6E", - "ciphertext": "F6D8945B2244345013B9C42EF12E33428B08DE08B67D749245D315F1", - "metadata_key_hmac": "5C8952B92EB8ADC934E67B68AC57A04172235C5803822F94F5A4D6EF02EBE042" - }, - { - "key_seed": "560238BF4D1284A55155B642EE1CB6D1F1259FA3E6E412D69C61832DBB0CC844", - "ldt_key": "FE8A459B03738D1C600093921A2CF605BD9EF3153B80E43EC0A79B09544922482FB8633B7B5737C9B35D90273EF6071B381CD71D56F11525B57279AFF80D744D", - "hmac_key": "86E0E51264643DE2E2935FE97A50724B2EDF9B9E9D29768B8834C7EB2DE168E0", - "adv_salt": "C3F5", - "plaintext": "095ADA0280AC300F54924AB297504E2C9E8E80258C", - "ciphertext": "0C4540C7030EA877ADF9DFEF23787A2059D4CD971A", - "metadata_key_hmac": "C253686143599E137D34B7B367A99351156427DAAF7823BCD78118FEFD172E27" - }, - { - "key_seed": "8D4A13F26ED5A961739C3EB2BFEA059BC99E44E7726CF1C922CF5220F2D3CDC1", - "ldt_key": "65046E006C2A7AE278CE1C099D4F07A1AE030D210D9662784CC8F51B065AA2AFEA7D4B8580A17929080B070252172637C9EBDEAF21A96378F2751456034C3481", - "hmac_key": "18CF2CF7420667D3A7FA6A479361A7F7E28161AAC5C6F84DA9C74EEE65B71EF7", - "adv_salt": "5436", - "plaintext": "B76F88C0F087756FC52FED378C69956785D975CA07CD6F56B5CE2564BCA4", - "ciphertext": "9B767EF93B9360A08F2E984D617446EF0B360C0FE1207C547664287EFAFD", - "metadata_key_hmac": "0114585B0BAC8F8EA1B88F01C3CB5B4D2F7A7059FFEACCF7A4F90505938D75D2" - }, - { - "key_seed": "C03CA925B56D7561DCFE958604A65C9A2AF5BD32901F4DB58CECAA9DDE86A785", - "ldt_key": "35F77C5C186F8F6DE64355A6FAC478B0311097B18B7272E2175074B2CC6B8D4565D4B496383013C18C6DF23D84DA5A502CADE24A8393A519CE58CE9295DD7463", - "hmac_key": "A9F3C2102306B52825ED579E454AC2D3C97043BFA018F9FD3C8E0A84ED22781F", - "adv_salt": "17FF", - "plaintext": "1435AE44951D8B30AF9F82FA7099789149A5CD704C292D09B56C", - "ciphertext": "4E77C59CF06B94DDA606D8837E60E1765F2B832562DA329C4A82", - "metadata_key_hmac": "0899362FB0F8C6D052AE49C70947C5BB576B0E7A03A341BD301B175C7BDAA185" - }, - { - "key_seed": "2DD921FAC7C94A14704DEC774BF3B966B6C605E359F8631B3F573AC88BE3A3EE", - "ldt_key": "6FCBBCC9738AED48819D5F410CC938EA41C5011B7C32B6B9C1D7F9F1699E7C55C7893C9752614226A94CBC441726D94F365BE068E5E641D8DF51D2FF14F183FA", - "hmac_key": "3FDF2E252A1D3DB8FC22F4FA3E4BB46E27FD9285F67ACAD4A3B18613C7429A23", - "adv_salt": "C63D", - "plaintext": "4E18456921ABB6CF637924DFACF7A9C3FAE58CDBBB9F", - "ciphertext": "C5A7BFDE9F216CBA9971122C3DF85C0BDEBB287222AA", - "metadata_key_hmac": "1C1CFA1B668CECE1CBBB580A84707E9B5CF30DD6F15ACF18741C52F0FE7767D3" - }, - { - "key_seed": "DCA956B5EEFDA5B3C69921BC348279470281A2530BC257E5232462CB1FC8B7D3", - "ldt_key": "A5CDF7F81CDA770C3445302A6FAE352D8F7CEE51CF40D9CF2CE8B726187497F9BC4DA1A8B6A55F7895AE12032B6DD2FA9451382E28306E20672E0D0E04FBB63E", - "hmac_key": "E5008AE8058FDF4051ACADBBC844D6C985DE056450EBD7146CE188DC5869307B", - "adv_salt": "90AC", - "plaintext": "384E8805B425963315323F490816717C9A5A", - "ciphertext": "502B16CAE050677D23B192893E594D9E5F02", - "metadata_key_hmac": "4BFF98CC40EEB672706674F6D21C8FDEAD9B52C90C7B2CF501633848BA2F5ECC" - }, - { - "key_seed": "40AF40B7FF79C424E70C7E054599A279C8431A8A512E775F0607726B13B3AE15", - "ldt_key": "35462ABCAA42D664176C8FAEEE17AD02448447B15DD737B4B755E251AB3884CA8EEC1EF3D4DB171936E0ADCFEDCC69A9C1B3F758685D126C2A4C1C129427B021", - "hmac_key": "E367639CB8320BF69D697FE3C7C0E5277671170E5214F4CA2352635242F6BF36", - "adv_salt": "2BFD", - "plaintext": "C5BDE767A457E7E723C6610F1C455F9DABBA438693AF9A642805", - "ciphertext": "4A4173275F50DA2D98A22343D2DAF2CF9C61FF087A3956613650", - "metadata_key_hmac": "B88209F17B55D83B71BA7980462B779C00424013C90AE9CEB12E0DBDFF064500" - }, - { - "key_seed": "FF5C96B3FD32837F21B5CC7F9F9EAB1ED11F89812965C2B28AA81A536441EB74", - "ldt_key": "9893C0DF1BCEC6EA99CB4C8CADFC83A42030428E7E7FD396A63CCA339A33E845A17D17CFB321682897E5181DAB5815CE194FCF8C05B037125B1E81B02B89CDD6", - "hmac_key": "77F7CE078AC8BE9E03C40FBCB45AB62713EC512A733A58DD3CAFD176EB8E3B1B", - "adv_salt": "66F9", - "plaintext": "5FD020213436384B7302E92E202AE739A20BF68394", - "ciphertext": "838C667C5CF02A36FB8026DD2F3540F9672D3C1728", - "metadata_key_hmac": "D3DCFE7C53089590B94130A04E76EA89523069EB225A07A734AF1660B2A23E6B" - }, - { - "key_seed": "6FAC7D59FF8BAB3DB3847956AC8DBD8B3519C08AF4C711F20D38CD3F567D2DE2", - "ldt_key": "D903C89A12961C3BCD38A3F19C8441ED0CF8916BA13B472E12474C18AE5C455088190BEB14245166D53AA16F98E72EF68CBDBC35E762D7CACA8E60CFB3711DF6", - "hmac_key": "AA70D3407F9776F3917982AFA2DD41029CFD07E819C4373C8FE08810DFC9D204", - "adv_salt": "F797", - "plaintext": "4C409543C6024CCA4F833B368B23E9B44AC6", - "ciphertext": "D3C399978ED47AC0C6BB5B5E57596B684900", - "metadata_key_hmac": "E530122F1737AB2C99ACA47BA0CE96F27291C34DD1F80508198F7408EC37D39B" - }, - { - "key_seed": "CCF31A1494E92113BDD49360A5BB7FFB31B8E0878FBBB40BC844EE5087DF5DF2", - "ldt_key": "7CB2F134F970F0D286D67F2DFA24C286EEE2D83FB111238DBB86F0402651B520B14AC172E2E16AB5105213E5289F6D51566079F1815CB2C5F7A9E3BE57FD9F15", - "hmac_key": "C7670A04ABB7A78F7BC2456E91C5C717B008E2B063EA9A6CD763189BE4484646", - "adv_salt": "E4EE", - "plaintext": "BA8F7B5E0099CB0254B6747A3D49C06EAA91", - "ciphertext": "490BF53B189F05A0C937DE2D8A7F0D7EBD5D", - "metadata_key_hmac": "0C64AA6E76896D4A4603A4AE2FE2EAFB55E3B3535D71FC284D835C031E55DB73" - }, - { - "key_seed": "3C77FC3A249EF67B375F97A0D14C4341236335BE81A955895CEB78BDE0E89BD2", - "ldt_key": "C282CBF603E1886AE361B89F87FBD22213E8B596EC303DD76A9764D4B9702389DE15C0212AC2DBD5662771A4B4073205BD4B28C5ACB9D24ACBB71DE21A50672C", - "hmac_key": "2CA4ACC4D15728C0BD9B97D9DED9C7002610BD8E7348AFD1FFE70A9EE0DD37AB", - "adv_salt": "C399", - "plaintext": "BB8B563AB689CE07F3AC5C836DC7AF75A150407E9AF7FAFD4A5E25", - "ciphertext": "A0EB44DB1F915D2E5AE43A9379FBB8F09E2AEE75D23CB48C4047A0", - "metadata_key_hmac": "35AD7B763E05D22D41BD8573CEF4BABB85640F8203BC944E50DDC193E44B2459" - }, - { - "key_seed": "8260021B76DD65A64D8BDE991230DDFC682B333C51A5B975E1BB86B5FDC45F4B", - "ldt_key": "1019E0760F6E99414F88B799938456C3819A09DE88F1DD02C8AC46473CAF0D75BBBE3A9E974C67476BA1239913140C0F899B9635F72429855B9F686E4FEDD529", - "hmac_key": "202513CEBD157D750D437F4148334114B1169D6B08FBBD9F4C8D9BCA29A65D3A", - "adv_salt": "8156", - "plaintext": "26B9909FD80BBC3E9C4C7498AFDCA0C6F4ECB6462E9D0F", - "ciphertext": "BE9420D32E1B19109C6BC153773A4897EAD24FB543CF39", - "metadata_key_hmac": "D9E9C1497DDA5DC914707D14F0D475B37991C4A97D6CBB412FE4295E30A969C2" - }, - { - "key_seed": "5AC98E6B28870A3B01BA153498F4902FDBC0841F3AA048262A82F6207DD95F55", - "ldt_key": "009867255A86E609C46E67B290F648B7E6B99EBC836E8C57506647C0821663B8BEFB31CEFC940A12738301260F77B974EC782ADECFF6ED8E3AF3E457D8F39980", - "hmac_key": "4CFB59FD5B32224CE9D5B20D7C5BA93B8A16CEDA3B1D44E1471425340CB2A61F", - "adv_salt": "4E72", - "plaintext": "C2664EDEA11131E747D4BEA585651ADA4B8125B3A38F5CA8FAEFD8", - "ciphertext": "B4D1B01AD0C7E3C8A71193517B3176A75B81049EE04F6DB5B18F21", - "metadata_key_hmac": "619272D9A524C2BD3D3AFCF8E356804A23AC4DF7FB041F1BEA35D77CC768A11A" - }, - { - "key_seed": "ED0A64DC30DD3247C5EA07A27BE1F02DB8057D663C1A4C88BAD61433E05EF966", - "ldt_key": "924D5FAD57CE4E565F9054F4C22D028E8865F8378BF2C9135579086FFE45D305A6D1008821FCA9E83ACFFBFCAB395F55985009F1E4DCA4CDD45E331590BFEB2D", - "hmac_key": "AB32E92C7272EE428445A5BF592228D59606C1D2E9EEE1892386676CF3D70E3B", - "adv_salt": "E8F7", - "plaintext": "3F3436D46DA3900D591FA3ABC6B2290DEA3F10A0AF", - "ciphertext": "56A16B25B8267ED32C87B9334083581BE0BF1B5BED", - "metadata_key_hmac": "BA3289FE992B1F99D0338293547506D3CD7991F7A4FC02818BF918B7A4193921" - }, - { - "key_seed": "C0197439FEC973B0DE7D6F6D365A2DA4FB4D50FE0D93888E6D734857EED03D29", - "ldt_key": "716964EEAAE8083896DB7CEDBF25F8EDDA965C6187B4A5FCE71730128D7601A2947B030CDD6B6FABC268AA696883FCB81332945DA5EECA2926D19EB69C87F427", - "hmac_key": "FA076FC072E2C3A3404D16A11285275D7F0C706DB3B9A73C4CDBE5CB6209C104", - "adv_salt": "7968", - "plaintext": "D63A94F053AE7F91C82EBB969894270D0C91A72BFA", - "ciphertext": "FE4C5EBF299363DE9E8366950896FEC5ED67088526", - "metadata_key_hmac": "43AA21A8E39F1B2B4AF529043D9C4585241DE221937EA81483457245D91DE00D" - }, - { - "key_seed": "697C43D66FDBD83CE464BEF25465DC1D8B638CDAEFA077A26C19605B4B682DCD", - "ldt_key": "4542703B2CFF1FB68AA0C3D2E2B1DA51BB7FFDBF909E22D414A2ECD4C05B4CD569305B18F437A8AD38AF621624377327DB77E9D9E5F5A2AE1E5275410A72F399", - "hmac_key": "79BB8B92830FFE7D861D7E983F00747F11B27E7E4CD894AAB98BFDADF2D85117", - "adv_salt": "0C0A", - "plaintext": "D1DCA4BBA2FF7D3AF46325F5CCD5A88702", - "ciphertext": "FE0ED60EE668D3B17CB88D2092AA97D455", - "metadata_key_hmac": "1AC786DEB74DFB2E6AFF4B6CBCA604D9D17AE479F0D803D15B8E349A3E0C2216" - }, - { - "key_seed": "06744EA084560A864AEB290170297DED5C75F501857C323BA8AFBDB98EC8A36A", - "ldt_key": "D512EBFB1CF9FAFD53ED2BD36B95311424DEC109D0736B1EA9E1DE6B1ACFD4B8C97361DDC8BE2BD00A8981923191ED8442C7249DEB595C8581BD79184FF86420", - "hmac_key": "D0855C61600EE6995650EE1CC1B6025A427A49797A3D28BCEC4C56F792A4FC56", - "adv_salt": "EAA6", - "plaintext": "A7305489DF9B70E57C6078EC6EC3929D08C2E25D7B3E3A", - "ciphertext": "42F28FAD9FF09D8DC1EE7DF691F9FA1073FF3069E500BF", - "metadata_key_hmac": "CACAE0755E5FB2B9252083B6E5B111974DBE8198E73DA9FA71F87CBF142946EF" - }, - { - "key_seed": "6FA27E2ACBF24626C245DAB2F9F0BA09F14D3CAD3546B04FE69DD0AC4A81696D", - "ldt_key": "013516054A4C325FE76F96AC9CD773062A7A413C5DBAEDB9E7E52CDF15E4314DB9F9F9AE11FA4E958CD847F233AA9895D135AA9E39BCBBA416061D7F821AB7EA", - "hmac_key": "F2DD61A7A2CA13301E561908FA0A4855D261E1E9376CFFFFAF0A0B1182AFDCB4", - "adv_salt": "19BF", - "plaintext": "61B445648D1A7DF53C2C4D2DC56533D0AAFA413EB14C4A8AC4F575", - "ciphertext": "E6A0956FCCB9E2B9FE858870329DA6ED95EB05E7CDBADE0B738220", - "metadata_key_hmac": "5F218B368DE8AAECFA1CDF6AF51F1FC8363F6EDF962F6EC73FFE46BE420BF229" - }, - { - "key_seed": "B38D67920F2C40376AB3FED7D17CE6A506113056878092435B2800F452FB3C73", - "ldt_key": "2CBCC0C06331A4DA6A89D6D71896C2A41952F303464B3CD7D3D40AA4F8ED40537ACA2DB1B25DA39BCD0EA450404394DA3BA381055E624A1A955B395C8F0F044A", - "hmac_key": "FD0ED8C3F2458CEFC7374500F1102AADC30C1E4B95FDE36B988B8F7CC21810ED", - "adv_salt": "C585", - "plaintext": "14BC22AB086A9C5CAEF9C8D017C7F27849324CED0C", - "ciphertext": "94073101F480749B2542BED8E629BD7B7DA8BEBB01", - "metadata_key_hmac": "1E8414AEE2B04DD29B49BE15DB713E63F0BB2D4733348E7D77CE8221D78FFE95" - }, - { - "key_seed": "6BD37AB62944CA4CEC25D73CAAC6F3498B34D6C2390EBE17E91B19863FBCBC6C", - "ldt_key": "48961462E6646A3F481373B6CCED96BC20CDA30FB664597DD35CE6292005E5470CEF79B662CCE6D730765D0443B7AADBF5A419332FB0CCFC0BEA069F85A0A792", - "hmac_key": "478E6E944FCCFEA4D38EB03DAE59EB00DE7EFAAAE537F8EE6BDE87DF5ABD8327", - "adv_salt": "2751", - "plaintext": "952910F1E3DCB83CEEA55422EF1C2CA4E46B1A04D970", - "ciphertext": "D906530759DFCBFD38D97B09BB9DAB63D68A7B7B9848", - "metadata_key_hmac": "FB65431090B30F67EFC457BE2A449D644BC83F2D5F1C717171ECFCFF82676F28" - }, - { - "key_seed": "A330634C116712EA137CE53722858AD6138F2CD90988BF158211ED5CE5182338", - "ldt_key": "8B4C490D6365F4A5A97286743D283E062A83D73DBAB6EAD6DC39C494F68AEDC0C00C58FEEA41E566EDCC4C3D63BBA6C1BFD904318060E945C329CC6F62F63B2E", - "hmac_key": "F25C43F900ACA2D340456D6840F1C3DC443DF2763091D939E93A53324D71E5D2", - "adv_salt": "4A3B", - "plaintext": "0355A87A074F53CD834D5F2238B0335D2CC277", - "ciphertext": "B730CE0C75511611828492F865AA841EA60028", - "metadata_key_hmac": "CB6CE48F7B1C5E06BB357EECFF068AFA13AF676DF66312968840E4D43037D627" - }, - { - "key_seed": "69605BAF6A2299BAB7A3117F501BAB2E153517A0575932A25CDD173C77804DA3", - "ldt_key": "5BE1FAF5E9929EDAB360C5674506D8A931CD94C18EAEC3D0D411788B2B80A2C79814DF26ED3FDB3B125F378FA89411C7C6EA2CCD8A76158D9360952832E1F364", - "hmac_key": "CC227C88EF67D8AA4973349DB2896027BB95C1AAA02CF64F0F8D5014CD368DC0", - "adv_salt": "DACD", - "plaintext": "9D04514DF277767EC7259E463B0F768C1158AFE8F98451716FD8", - "ciphertext": "F6A099E137900CF08E4AE3C425866DE178D1C0FAD9E34AD5DEF0", - "metadata_key_hmac": "C42A041EF294EBE5148260BA7B3E79C516D0BB68866F67DFC676A4C50A7CF17A" - }, - { - "key_seed": "A8E067D4DAF508F350A6053DD414B892F61022DB040BE37C41525E856042C043", - "ldt_key": "EAA8C9DB71F86D712FB5F37017AE755D13FF856BD8AAB483C9DAF1E057BD0C0DBB0FA91FC6A6F543AB8904AB427CE7A74EA033C30D08CD7F7090E08BABC83594", - "hmac_key": "BE0B4023C4F3EAF51F78C5B3FEC4265B6ACE0D1533F87800419CCE566FB65327", - "adv_salt": "4769", - "plaintext": "5A7359231F0D71558583BD2ED0A6132EE1B883A3E007BF", - "ciphertext": "E1B783C4E61A5D7E9C0A1C3D7B9FE3C1B3A32EB00B8BC8", - "metadata_key_hmac": "E77F1DDB4AB574B61ABC25A4A401D1B2D5C56208821C7969DBAA51E0AD8655DA" - }, - { - "key_seed": "33BF72DF056F642EF3ECE670B6DB89AAACEC79714C08EBFA3D67D5337B10CEC5", - "ldt_key": "7E69EF6784947FB842CAC947892EB92E25998B4C351C52B47B1FF8BED34FD9B614E4B6C0DBC473B8403D9E83538441592A85A7DD623893CDDDBA93BA091843FD", - "hmac_key": "F79E99ECA90D7B6E1BBD7A56D9D162E4C997B8C13C3EB67ACFDF6C45435BEA7B", - "adv_salt": "0795", - "plaintext": "8259E9342572AAE69EB853F4ED235A4E2B352042225064", - "ciphertext": "AD48FC27DDACE86F2B30D057439BA73BE6B2481F801BCE", - "metadata_key_hmac": "F81CDA4ADF43CFEE4FCA7B5504741F3BFE4C777FE27B5BC9911E28F68358B792" - }, - { - "key_seed": "23FD4FA8106C7B8A988BA2E9D7FF5960DDF21A93B153952F31BB1CD7C3D8FDB4", - "ldt_key": "7DC8CFC25C60B5F3D0CC05B0CA4CBF0AE292F78E8B25CF18241E10F55FB86C7674242A42DC27BC252922D9FCB8524BBDE9146BE4F2EF5B1D20AE9473DE54F12A", - "hmac_key": "81C08850212A281C3A1FCBED4E70A460A91A1A3C8DBBE77C5615DDBD3A1A0058", - "adv_salt": "5141", - "plaintext": "99465FF4B2E920F83F0FD5680C7AA33886C7DB872687069ECC7DAB", - "ciphertext": "FE2E63AEE44DAB9E4C8FAD0DCD5BD8E4C770292E344B4D07777617", - "metadata_key_hmac": "C8A25EC974F10643E7092B40A116667D302C459ACD15CFA531159E224A61D7ED" - }, - { - "key_seed": "7B5E0E72796A7CDE98719D8B0DBCCC6CFD636C6DBE476F8A206FC8F78B12BA7F", - "ldt_key": "8FA267D43BFB36D59C970771A15B08651251F4F2DDA6CF223258469F883D1099BC8C0AF94EDDD649A4DC537E55A7782278150A442D516C61B561313787CB497E", - "hmac_key": "90C88F0C2CB1A762C19D250F3F7E1AA217059CCAEAD8FE13649FDD9563846EE7", - "adv_salt": "38A4", - "plaintext": "F23D41E3C96B3EDD64BB32DA96E7127DDA561CE75690DBC84313", - "ciphertext": "8D4479180E250BDCAF93A1C7254B12CEA1CAE90622D2C5617037", - "metadata_key_hmac": "8346376CFE03573F9105464067C53CE38C712FD42CE6367B5DC019040EE66219" - }, - { - "key_seed": "FD6EF6225C64BAF3942E9CC8B8B2FB31333DD7C4CD0371D8E7A8BFACD67A5406", - "ldt_key": "BD5ECC8DC600DCF4BB0CF4FF255406325329EEB2315E9AF6826E95C00E118F2A04CD9801B87C108F098F77AAB3A6DB3CF7D1AFA2A4A44E698C9B6C28CDDE387F", - "hmac_key": "60D11CC44952B70588BC218186A89ED0F6C88DA4149C8F812F162470694250F4", - "adv_salt": "8A82", - "plaintext": "4CDD507A6EF676F63838CB94CD080FDC1FC415403217195FA2", - "ciphertext": "8D4A363B48EC2E7DE7F394BD19C68863DD8B185209538A00E5", - "metadata_key_hmac": "4A7AF9E6E406F73B01F669681064182BCF68F34EF4B2D7CF49B7A92E9BD847AC" - }, - { - "key_seed": "C7D86CDFD6C4CC20A6E02F16F141526DA17D2023454CEE6B49B7DD75FC023B8C", - "ldt_key": "36CF3CF171CE8B6D96062FE3A388FA871B018880F639A19FA89B2012F43378C02437A2F1EE170EE196797897A88FB145D8CA1FF5F2220A6EE6C08CCCCBCAA161", - "hmac_key": "7FC77CEF16D868F5DF038049B1679244F9A926395FE78BC4E30BDFF8815D2309", - "adv_salt": "0F1D", - "plaintext": "AC56E8D0B4BD95E907E79160B5C9164A9CB6D1B632052A", - "ciphertext": "7507293BA55C77821BB0434B0B80F379E7E92230C5E714", - "metadata_key_hmac": "2B22BEED4D9C8976E67972769003479B96D65E348C67765538D53D0BF13F1959" - }, - { - "key_seed": "B9EF34F19378FFDDCD6A037B700B7C1249CB8D23861DB2BE4A82F8B60B971232", - "ldt_key": "22A3598D49087AEBA3EB405F8E2BD1F5D3B493C73C6F04A208A58E250DB094E9925F0F5597D6099501FBE3FAC9C5F352D1A50A7822A619F972298451CBEE149D", - "hmac_key": "C20A8A2466913A13F5274B6ADC1672DECA17F8DCD93993ED259131B3D26247DB", - "adv_salt": "128C", - "plaintext": "3CB22D13BCF6B49ACBF0307C977BEF4AF024C5E939C1", - "ciphertext": "658816AF0BA9938CC80BC657342405FB58B4F5C69A70", - "metadata_key_hmac": "2C676E6FBA574FF9AF15F9E52742E43D677DE1EEAAE68F83ED265D62CB952748" - }, - { - "key_seed": "F6E2BCDE6535687F2BEE7D31CEF07C094A4291368DC9E0D29E4E7A84743E0617", - "ldt_key": "F3EFC45D8829FA28138A943224D13E5DF087F4020ED84AFAA136ED4F8D1324F53F45ADA3F989B70BE718EB1FBCA33EC100D1FE2D84D2B8BA8FB2C862A4CB07B1", - "hmac_key": "47A87F2ADC7E47B0E40110AB53721539CCBBD7E83FE51E9CB027C9A8B9399278", - "adv_salt": "6310", - "plaintext": "BACB663633EC8A203B8E47CC78E2FC3C57A4353D0D", - "ciphertext": "2146B3391C532606207377D6DD7129C3BA2EFC54BB", - "metadata_key_hmac": "D98EF41807B9CEF28CBEEB1471FE28D288952F8724577C00E71583185C490953" - }, - { - "key_seed": "BBFFC330C5116DA19A7C6A5E8B4316E6A5B2F1BC5F4D20D8C5860FD88DCEB878", - "ldt_key": "E87D1C153AA1550030306A646114F51AD0540E09FCFF9FE540733688690D03BF2602466AF95EA855B8BED74433A033E3C299BED3A38FE0790C631B0D04A04EDA", - "hmac_key": "62B2034BA3F1AF080C0669B5F0858AEE56CE7A8B33EFD59AD37018D5CEEED31F", - "adv_salt": "BD55", - "plaintext": "CFAD209C744144A5B30F993907BAE63FA71C", - "ciphertext": "181A4E56F70F0430D21D0DD4FB14A1B7FAD1", - "metadata_key_hmac": "28397F3D55EF8C0E29229EA51D6A7CE95C0803C5E149CD8C9AA550991D08A4EC" - }, - { - "key_seed": "4FDFE79A62944A011A72126D4E68B5CE66169C91CA7CF5F9674193623C616FAC", - "ldt_key": "DD8C89D4416DB6F6A2684AD39BDFE617E37FB63FA61299A9DB89B72239FDBC977B0CB0602BA265AA59D8FCF97A89E0A0A51E0E160447358B0F44C62E187142A1", - "hmac_key": "8678D9FB5D39557B280134284789042FA9C7DEDBAB36197381499CF53366AA47", - "adv_salt": "68DE", - "plaintext": "810CD81E8E65E2ECF1FB83BC041E94E7E873DAEF0B64447D59BBDD421B", - "ciphertext": "3A1497277E3A3F20C43E245B947C34001CE9188AFFFA38F4FAAED972B4", - "metadata_key_hmac": "B2552A6641B7922F972D62FE82637170920586808086357A48BA3ADAF9AE7446" - }, - { - "key_seed": "189B61463E970CFB7592E88303F0A8DC86CDDFCDC26BAF74A8D68D97C210E23A", - "ldt_key": "393558113FCFE50A4730736EF9EA91C9D5DE4CAE137BE0FDCC1094C0A899DAED1C421895C90DDF843BF2575CEFAEE46F070684A6A33397AF93CBD9D7FC1CEBB6", - "hmac_key": "D072CF232AD840B8E603F8E4714CB511117C0FC0BDE0F6A51C5F514C9C9FF428", - "adv_salt": "3AB1", - "plaintext": "97ACE46DBEB775F42AC8D738A254BEE3A6CA83062349861458F4B5745495E7", - "ciphertext": "FDE78BE771E2174F182BC153368533F4ECAB80DABD8C18A3849E9AAF0AF60C", - "metadata_key_hmac": "5B95374AB9E06D61E9C2FFDD88D28A9A78EF484ED7E2F3884FA10C42B82D43A4" - }, - { - "key_seed": "8099925AB4138B87D1945B94B5C38D8E409392A59A0B8571C5D6F2F9CB35FA3B", - "ldt_key": "0A0E7DDC21515365D406EC8A51827740CCF512BB2AC70A85A9B14149706DDD62AC43ED590EC9A27E3560F8F9FB6B106E0F08ABA0616D7C5AC6E3F4F4B1D0F0BE", - "hmac_key": "734EB396DC44EFC2928F7A19707231B7B98B5BEBC101CE7C6E9561D130C4D8CB", - "adv_salt": "596B", - "plaintext": "64DD65CF714E17B310A8949C2B171F1F931CE19AAB3A8AC7C6F0B7AF", - "ciphertext": "9B8DA9C7182734B97C0E2BF2702689C95F593A61E60ED5B9FB2506F1", - "metadata_key_hmac": "5C45C2C3FFEA97083F007F084EC0A8E21D9C827AE8C15B3ED895A99B3158C986" - }, - { - "key_seed": "27041C6BAC8D938489F45F322E201C7F77692E29605F162ABE43BC7DD443A922", - "ldt_key": "DA4669A8269237CD04D1E2BA5077C988860F0AE9BCAEBE0F72BFAF63DA6825D5AF7A8E7A2AB8A607C0434BC618158090E476EDF87B7C65D120E1BF4ED98C626D", - "hmac_key": "DA52FD9EF396CB4550143E011683735589D8D3B92FF6D1BFBFFE6E9B7C1E19CE", - "adv_salt": "0D49", - "plaintext": "97D24BFCA3E2414657302E6388E0CE5FE8DC8E5C", - "ciphertext": "F90608E4C090D7A4EFC127295EDC0BFB863422CF", - "metadata_key_hmac": "D1C309C36E66F33670D6FDA0EE05E0703669D7231A1415ABA0ADED32844F2A36" - }, - { - "key_seed": "8D6A7B1B75A42EF4D0D765FC5E349BFECAAA5F2F44FF401B69A9A6B3A592C5A5", - "ldt_key": "7A0DB884E2DFCC2C902BEA55C4D9AE023A090226294DA6BDB13D6DB9EAE4AD4B836EAE4A76C1505BE7EB4C8200BE0E7671849A276A9E86AF9B8114B0C59A1529", - "hmac_key": "774BBB9ED55FF7B5F7E7067A93D43EBF39A848C053A6F7CAFB470765EE051562", - "adv_salt": "54EC", - "plaintext": "D5B99BD450181B46608DCBE86970A4461676E3350493", - "ciphertext": "72360EE5F4E00AD259BA7B27D44DFBAB8E1D7E87FFCA", - "metadata_key_hmac": "B6874A01C4C4134AFA8D2617C0E12DC5E2933DC50E4965EDB516037D389EFC51" - }, - { - "key_seed": "8B35CEAED75AB9BC440007C1FDEB67BDE737C1BBC5A47151CED4AEC30E316A3D", - "ldt_key": "70AD11208A009AC067C91BE445D1161555EF0107F7988334885ABE4E795F44B913F8704825396F3619F0851F5462CCCC378DD3B6E58527290D2CDC11C2CFC408", - "hmac_key": "F86E2AC57F9CEF2447AE1861A964BD6438F3119032B62ADA5D3CB0DB426FA1E6", - "adv_salt": "10A1", - "plaintext": "DEC03FA063713924FC5D1B496C66188C73F61B", - "ciphertext": "91E43CFCA71C439A7B3833F44643A2EF96F796", - "metadata_key_hmac": "8DFAA644D383B7711E0915EB2298F50E68980374E82ABAD0BD6E748317CC2427" - }, - { - "key_seed": "4B6529FE3922521F7E60426FEA8BB5AAB0F937697887C0A419CD7689F408EF1B", - "ldt_key": "DCB3850034660D35BD5653ABAC9B74D09312A129124BB088D987F2A226ADDDC6CE3C9083DDF2BF4E5F4C2DBA7F54EC28C7325DEF05B4A6F7701CD43E5A44FFE4", - "hmac_key": "70BBCB078B01A2B5D9AE6DB6FD3FF814D6858E8D1884052526B3948DE0159E1C", - "adv_salt": "1702", - "plaintext": "06BF92FEBEE1E3517771754F6B9E6CCA43A6B466", - "ciphertext": "1973E758175EBE6AAC496F454BA5E962620206B5", - "metadata_key_hmac": "BD57BCD419CC438CD03FA8C2DD95880248DC114FF8B95272D2A79F1AC30AC1AC" - }, - { - "key_seed": "54E3854608122E139E0385AD5DAC9FE9B6632EE73DE765C15235BD2B71D54E4B", - "ldt_key": "B3E9D65E8A2CD6CBDF96F023ADCC82D446C22774C2472C7B5E0042A095A12279606B03BC4FA9FBF42CE1BFBA96E972E27707E9DBA555EF011CED92C138792553", - "hmac_key": "71929D03409011AC1217D222EED45EA0BE580E82814A00C03FBDE9BE40EEE005", - "adv_salt": "A6C4", - "plaintext": "63F169242519545BF6BC6C2B41F07D6532789928FFE91843F9197228EA", - "ciphertext": "C18A5C4DB3C1A5365A46E2866AEE404FE12CC6EBCCA12BBF061AA83822", - "metadata_key_hmac": "9E11391EA502FD1304D9C15A0FF8BB707571EE09E0EFB44A7D612C7E5216C9D6" - }, - { - "key_seed": "A00D4DCE27F6531056891C93C22D2A61830191A296B5BBE3760D3B13FF548F61", - "ldt_key": "6FACCF6AA86CB8F0C05991AFDFD57C4A06C58DC6195E0BCFA426C66DE04A2779B62E7BA6882589B825F9192D31D3C91268D70D425F52F961EF3D1C9B045F01F2", - "hmac_key": "E19B1E9F5C3355A52C6872225EF92CB09686F4B3CFDC883B7A01DA60D897613A", - "adv_salt": "324F", - "plaintext": "C103C7B8183BB72CF30A1CCCFF6E6774AA08AC", - "ciphertext": "7D328033E813212D6DC0B577609E3F0696A4BD", - "metadata_key_hmac": "407C1AE2B01585EDED1FC57AEE81D5DB54A2111DE3C131E4DD61EF8F22FDAEB4" - }, - { - "key_seed": "1CCF58E167E1A6D7BAFB4D5DBF7AECFE1A5B067FDE2F4FE1C6A7622980E39FFE", - "ldt_key": "BD52C9294BEE6999D032FF607ADD946DAF8A83122C608C473133D778D35003955F2DFD35FA136053C24FB10A40408408F5011BAE86544282D8C02B2B050DB963", - "hmac_key": "1CA6D8D35B2B32622CD6623F82476319AF0D0C2A59BB3AC9C9088ED78CD3ABBD", - "adv_salt": "A659", - "plaintext": "6F0371455A75B8874CA29067E946B1624AF75B0D2E77E569", - "ciphertext": "54125A4C0B9084F8205FDBB573BA70FE3D75682066FE4DD1", - "metadata_key_hmac": "174B80653DC7291F1824CF045B6EECEA5F66EF1FDE754FA3D42BEF0AE05CCC26" - }, - { - "key_seed": "EADCA313267A42211A53EC7EC955511AA3F444D68A3E4E57019ADFB7F10B94CB", - "ldt_key": "D2461991FF65B9D300D378D6463D053CFEE4741F9D390249CC95382DED5EF5B26500BA102150750F6337D9E5EDF2D979B8BC0668C85AFF90DF7422512B6A81D6", - "hmac_key": "59D8DFAE1D603565D17953FF0FD0BC2AB914564EEE42A223429B91C8313BA1A7", - "adv_salt": "ACB2", - "plaintext": "08EF1F46D78A71F319673E8B33E147DC", - "ciphertext": "67390B3BB369F4B2E1997A2FB7D922EA", - "metadata_key_hmac": "434B0A94E392E8606776968287F22ADD224A6DE23F3F8AB39874111777870EEB" - }, - { - "key_seed": "1A94D342C30CF5932A44139C85C581A8228B578AFB653F957BAE541DE577253D", - "ldt_key": "8C5E585691A61F6C5E87ACD997CFC85ABF402D2C9A0266327B7BBED2EC75B324EEBE7BE2CD604BF9874EDF9B022088DD4717FA99B667D6E4160023F967AE3C07", - "hmac_key": "07F3BDE3BBE5979FCAC7B96D93D596701454CCF21F569139AC613A74F9A4E2B8", - "adv_salt": "3A6B", - "plaintext": "8C83B122A29130586B7CE6E71EA61C2B7E2F274ED5A6B11B04B4B0", - "ciphertext": "FDC37C036F089E4367E6447E69F24F3FB7D030E9CE0FFEC54F7F6E", - "metadata_key_hmac": "494BD98D79B6A4B38BB78B2BF222AED6B7777786D39078934C17E63C5F9F2EDD" - }, - { - "key_seed": "81B65DE1BF1A9E9A601BC8F928ED4A315B9FAC0B0919EE1E8E3F01454658FFD6", - "ldt_key": "0EE3259B8AF00CEBEF6D5891E1D5F658F90DEBAE478CF40C30DAE5199DEC7781CE445D3A59C9DC1DFEA5E19D5BEDB0E9A8BFC214BAF348E8C859B355CB2F2ECE", - "hmac_key": "E956219F0B6C7DBC66F6E990D34F41030337F56A811DC39493EE2887DA7D697F", - "adv_salt": "1892", - "plaintext": "D62AF513F9018FD945DAE0B78C4145C38E", - "ciphertext": "7D63B318D50A7DB01E3509E8911D4488BF", - "metadata_key_hmac": "C9FFC2BE2805B4967860F7B219839125BC710AF1AFC971A08DD1721BDF5E0E87" - }, - { - "key_seed": "BE1097BA75EE5513684D071BBC909906C8791D6678926E7EE293742772A6E395", - "ldt_key": "71DDF7824BA202935E11501FF5B3D33114B614FCC4649A18A9611F75E65E101D53AE13D6538200D77FC0477E157898B7A562BAE4DBC0E4693C6F3DD48D206EE7", - "hmac_key": "E42071F1DE0ED1B358339C7DAD5697738973DC9BCF282FA5A182D3B86C1BC7F5", - "adv_salt": "B3D0", - "plaintext": "7749F4AFFA858AC1962C597E7323E5A495", - "ciphertext": "799DD1320252E90B6A89DE5F83AA9F79B7", - "metadata_key_hmac": "26CB000B6639FF02FE93A11DA57A2B2B98B67F450D46339BD9B21D693DEFEF5C" - }, - { - "key_seed": "5782D9EC66D31341A49021FA62B60D038CB04B653A1C1FC7F28A0ADB7CC89E39", - "ldt_key": "D4FB828808CB8148FD1839E0274FBE3727A51C38FDADCF5C91D9F28EA0019A43E1A78E7BA1B4051A632A350A22A035668FF61EBB7D960D6426517954A556F940", - "hmac_key": "A7020D0F20CCB3183355A37774B0983D28BF39409C4562EBC6D52056D2E170A8", - "adv_salt": "2A1D", - "plaintext": "2098F09B094B82F479402565141E670DA2CC6A06E2F06C910C", - "ciphertext": "484856873B3465A14B86D158AA65F72E69F6403CB84232D34F", - "metadata_key_hmac": "B5BDA9519DD3E98879D8B0627EA819913B6C4458E04CF3BB803A39559D73D55F" - }, - { - "key_seed": "FDC7CC332EB122DC5E3E2D2F8E45400636B4E7780FE7169004AA7E20C6B27130", - "ldt_key": "7EE39F738F481B4FCB8DD720CBD46F9CB9F424B75C0C4C25B0394767C00A7D5DC4091F377828A5276C61FB5D2D25DD0873B4ACEC4428CDECA1EA8178C9E30023", - "hmac_key": "8B27C2CA40A928E47B60CEE90E993CBD5E959FE471885A6C4717544F26276152", - "adv_salt": "A815", - "plaintext": "1EB3C2CE847B078594064E8A762558E428534448D3ACADB01C", - "ciphertext": "E509A43D2204C464AFAD4B9A6616EB44C52E160B13E17689AF", - "metadata_key_hmac": "0D25212C693FB0E67FE3AEFFC92E5328967F025A80DAC82BEA43A90BE46ED80F" - }, - { - "key_seed": "6A8660E01FB845F36CF850711077B4C826142E2A0169AB8321D6177FAC49315C", - "ldt_key": "CC97042F35D91AB245E70FC2C6D5A5CCA40AC070EA7C8FCFDCEF1F9037C79B2B31D4EBD030F0C941AE7D29681A505340E8C8A7410A9A8546582A4BE7859657F0", - "hmac_key": "A925E11A741C1EE11E49A604C5FF69EA7C4FAEAE9D0044F783B75872BA2D709D", - "adv_salt": "4723", - "plaintext": "B0675497FED81C60FC9E76654E13B03CFB", - "ciphertext": "98278F68BF00BAF740642120B69AD28A5A", - "metadata_key_hmac": "B623C6CF484872985B8DD0596020D88EF03FBD1DC7761C80648C66FCF40480AD" - }, - { - "key_seed": "B5C9178C083BAEDCAD97A7A4757B66C3DC64B03064D4F6686BE8C202DB1809AA", - "ldt_key": "356145719EE39F953142FF07290DADA51C4B4F442BC6F5D67D086C16EC875D736AD5E2FF44ABB344D1F5B9F1254777AE5E86FB767F5441ED3A4F6262635E77E9", - "hmac_key": "22A3AB00EE4741901558C6567F22A6A88FAF34FC7AC4C15EED7F6615DFC433AC", - "adv_salt": "421F", - "plaintext": "38A3F2DC36199F411EB565D12758DA9C51E38230", - "ciphertext": "15247ACADE7CA745F6C37811B99870D418AEDEB8", - "metadata_key_hmac": "CDD0ACC27C3DEABF89071CC2F2592C07E1009788B49EA7315208124250E4561C" - }, - { - "key_seed": "07DD86FAB6F73009F610F5F3FFE76BB8CA257AD8A5E9B8D27DC8CCBE948193AC", - "ldt_key": "435CF9F5CF8075B2C227A9E95C35F747BD99A53594F96EF778DEB8BE8D988B901C4F98319EBD55DA91046E382FD5504F1373D504002AD943633896AC87A6ECB0", - "hmac_key": "4EDC9928BA58B8287E0FEE3968310BACE74C344227A2D3AC4C3F33CED21B518F", - "adv_salt": "4402", - "plaintext": "BCB7CABAB0B4EB14638E60766A517E80CFFE1EAA9BCACBB1", - "ciphertext": "36D2F9CB37FA4F45B373145A66DB0A4D3C89BB5BA39ACEB6", - "metadata_key_hmac": "40222A55C432B13508AEB67112ED0945A8808CFCBD29A54BBCAF70DD9FB1DA1A" - }, - { - "key_seed": "B4D47064FC92CDBF3E0204AAFECA67DB2E1397189162B0693F59ABA9373287D3", - "ldt_key": "7776476A2E73E102B3F8E78448C9663FB7D12692DAC2988F029ED52D904ACF2476A4B85781CCED68E8C444A8F402C496E2FCE6082243FCDA7425C642CEFA13EA", - "hmac_key": "65F98BA0F2F2B46EC0ED7563B4955F9EA7142E810BF86F455FC86D1C1FEE492D", - "adv_salt": "3C04", - "plaintext": "63ACDEBCB100020E6BBE3E34E9B2A0F8EF862246E2", - "ciphertext": "C5379E612483BDF2220AFCDE21250E167749B0F7D5", - "metadata_key_hmac": "646B1C7EE957D187E4EC607E2BCCD9A6398241F8A7277677A3218F782AFB33F5" - }, - { - "key_seed": "B77F947E37384AD02CE4CB1A181288A1A80F3D3968E73449BBF3B9B2C27EDA58", - "ldt_key": "621AD29E712745EF9821D30F29D1BD4E707200515F732E8ECD68A6BE6A0864E7E39A7586B78A679B82A87523AB0A02BEF3FE75275D4523CB269D591EF3AC36DC", - "hmac_key": "B4989CCCD6DA89C58DFDAC6A6AF7428466E018C00AF396E62317B36EE7A6A63F", - "adv_salt": "2223", - "plaintext": "C571D5F394E9640B495A9BB26A938900F928CE45BE00C519F342B4DB3F18", - "ciphertext": "DF5FE7389AE4D8A881AFEA097EBFCA7EBD81F8F507F308824102C316411C", - "metadata_key_hmac": "CA1FAB06AA37630DE95595CEEDCE1D291F51C10C8DC1876DA29C701756882AE4" - }, - { - "key_seed": "F8D6F018EDF3CE25D03D13438A647E211277E1285D50F12F521FBF0AEF6C17C2", - "ldt_key": "BEA6A0848AAA447CAE44D403B60F4A94C3731568A87626583DC43DF1A1241D8A39F42842D590FB142BF9A2508D5B767F184742A977D6B458F037F80F9CC8E4D5", - "hmac_key": "D0E35F7B52D04FF1C8CA9F39E85FCA40DF6BAFD03268BA64FF12C51AA4C0BD11", - "adv_salt": "CD19", - "plaintext": "00985AD94B8D2C93EA3642494A5B0EF620BE", - "ciphertext": "AF7A3074242E41A5735AC3E823576BD7F42E", - "metadata_key_hmac": "E6D9B0ECD04A8D1C03DEF5F8AE5CDEF48B874D24DF5CC2937E2EFE0588ED367B" - }, - { - "key_seed": "A9C55D893A3A40A15929B967FED3BC52B2A38195D7340EBB10B99E1942782FA2", - "ldt_key": "F8A20F71F22B6C1ADD9C5AC3524C618DD74EECE7B81BE0EB8D54F1962613C808252DE287825D49680208AFBC6D1D85B0E05B3602D58466158ED77DE09E6B2343", - "hmac_key": "605B915D16AD2F783038C935003237AE59E9123F35B2BB13287BADCEBC18A289", - "adv_salt": "934B", - "plaintext": "95216F3A7043C18D63195513FCE1C7C1FDA6545200B6B5E2BAD1822476C5", - "ciphertext": "FB4C08C4E8A1474185FD12274E5B04DF923C2E517035A54D74B5CD5D164F", - "metadata_key_hmac": "0091FFC18E5BF1C1C22E212161955A2DC9BEFA4BE7DE3F0D10B3751F83E8E36B" - }, - { - "key_seed": "0FC8200E3516D1C17547ADD4496BA06202C7620EBCC06F8FEE5880130595D2AA", - "ldt_key": "ACB2F0E90CD88B29993F162EA049077D24B15EE104F8252408BECA2B9CA6A83B9B9016FC763ACF5127EE6C4B0C477851A166338ADB8FDCB4DFCFFD56E6743782", - "hmac_key": "FF74B5CD682C9C50E2CA77494394DDB74946141744A52CE6569EB61FE5F2D5C0", - "adv_salt": "5FE3", - "plaintext": "0662C83A21E9A604137ED3E4B476F1BFBF80712DA3F86A27647B", - "ciphertext": "B78C902BE09389E33668773351AAFF1AF8065F4E08C10C5C5CFB", - "metadata_key_hmac": "7F8FA03FD2E844C71B9D28AC291EA331DC1A25B242428D0F9C769CAC71FC4191" - }, - { - "key_seed": "FB04727819609193D77B0B6669BACB4538817C41F0D75C43E5E04EF2ABC307A7", - "ldt_key": "D980A40193A2312B742441AA435A206CDD3381FB0BFDDFD5BC8F75F95AA0AE27563D43866908E1A1F7DA9B3CE4DC42EA0A93D167FF44995B0563925CAF798260", - "hmac_key": "33B0446E8330D843500A02DA179C2624DD283C821405B812980B1BBC720AAE70", - "adv_salt": "4428", - "plaintext": "FE1BEAD3B9682E051481BD5C72B4D571A465DB78B96E", - "ciphertext": "800C8077C465EAF7AC191D5C20978FA46B05B81F9127", - "metadata_key_hmac": "7746FD13AA424EAA1F1CC6F05D195CEAE45872C3F822E8C1BB0487CF18E031CC" - }, - { - "key_seed": "3E6D4FF8DFD8FAC1AA76677789215EDC8FDFC88CF1143CA6DC1CA4D4A9E3F3A4", - "ldt_key": "B881F04DDE3BBF8E24C721D5FE186565819AFF6C50DA26CEB117B15DA21949EC9F601C37C9DC51C6E92DEE3D31F46297764A3B6BD56A63B17E448E621F7EAD6B", - "hmac_key": "3EEA351F7303E297DF360C4AC86DA755EE8724DB9D572A7516E8EB22561220CB", - "adv_salt": "3EB4", - "plaintext": "E54462C8E85DF7A358DDD7EF6134DF9779AED4", - "ciphertext": "BE71CF06B610CCFFA653F533ACE83D8234C706", - "metadata_key_hmac": "E3ED0DDFACA9D8A6945B83963C1EC4C49599BE0D5FA2079B34675AEBD21990FC" - }, - { - "key_seed": "E52D51F47DB88BA1E0A9585E119F45F7061C4ED01901DB63D1B068B77F2FA539", - "ldt_key": "E81988DDDE4B0C3FC9A91E8A07FEFE43393FF0A74720E0FE06891ECB154E7F721D4221BD43E3AF18F6BD8645650B31FAF7E70BD7C52FF820202F57BA920C7044", - "hmac_key": "C4ACDE87225B126700F0C9036DD2CDA1497655EE3DDB7F01EF411A51D22277D9", - "adv_salt": "09A0", - "plaintext": "09E63DBBDB48FF0D0B7D32A1268B200E6E1987", - "ciphertext": "718657B2C4DAC9368253B5DE0126FFD5131C22", - "metadata_key_hmac": "70576A2E080F91CAD7B4B3F9E45DB712F4523B2707DB196586BDF45946CE6B24" - }, - { - "key_seed": "B071FD22BE44144541BDEED68C9CBAEBE48B88FD6692F027F5AF1FCB15BB25EC", - "ldt_key": "5676B0350FCBDA91930AC19BDAA988472218C1D9E1224FAFEB082C8E049CAEB4BDB11249C40DA4105FE12CD6B23C8DD666465CFC3DC350BE62A338F3658CA1F3", - "hmac_key": "5F9A5EE4B1A55ECD54BBFA014DA8B054CFFFC1865E7B39E3359ABED7972616E4", - "adv_salt": "E4BF", - "plaintext": "1B9F88419F3C2CCFDFFF021113BAE89C7C232041D2AD85B96839E090", - "ciphertext": "9926F08F0A1CF58A5F7C97E7F2D916ED9463B3E0F5DF46215A0AF4C3", - "metadata_key_hmac": "751159135359FCC488029F43CB316B2FA26D0FDBED8ACCAA83EA2F4A8F8DB16D" - }, - { - "key_seed": "61AE93DBBABCBD1160D595F3692A078E6FFB8BE572DD11E19507CD7BA37EDA5F", - "ldt_key": "768CE6268EA881104C3CDB24244DAD5CE28E1B96F78ACA154671AD68FC96C9990F353968506BC547A615C4A6464574C5EB52DB83429C5FDA56678E7B7A3D632C", - "hmac_key": "E1E1B97C2CC8458D9812E692FAD651E125B08D281BF6EBBA94CD18A80924FCBC", - "adv_salt": "6874", - "plaintext": "BADD300ED46C1A6138E478AB27015381D26709694640CB649CE31C6D9CFACB", - "ciphertext": "BEBAC204B309701E1BE26584C9CC920C5530FC92903E53E39DAF9A27049122", - "metadata_key_hmac": "2E6B2BE8E00EB55E18D0E916CADD88B7EC4872EB487808096E7B82927E440C03" - }, - { - "key_seed": "828642B20291961F8938B4F80864C753CC18537BDC1EEF296D4743AC5FC042AB", - "ldt_key": "D468DFD9CDF067F701C8818F4360ADAE108FF5C3937A2BA5BF1C6E23A61810C666E5366457D0857A66EB0A47DD9F644781F07CB07881E5E79779832FCB71C490", - "hmac_key": "FE5F79F376BD8E8A38E774662F1C123BA9BF6FF210AE3D82F23741133ABF799E", - "adv_salt": "D4FD", - "plaintext": "A64B069FDDB299DFE6117B2B8E53550C576441C76A77BF6EE9F4AEFF", - "ciphertext": "1550E8E7792D7918A1D2CFCD0A568EDFCA72B6581BE4B937A682800B", - "metadata_key_hmac": "197295A9BB48590F804F2CBD75360B915FAEFDA7DFC2897C04846F35ED279B19" - }, - { - "key_seed": "64D4CF95291870854D9A64B132AF05EECE52527D2EBF7AA44E3F558990EA4B63", - "ldt_key": "FAADF11DE2EE8B2428E8702E17CBD16118D153ED85BFD82EC0384DB687B86EAD71460E7617C7C74D7F87A4FAF4BEFF85EAE680D81480612932E28EB22EC2430B", - "hmac_key": "B9335023F73FE5D226EC79BC61F766A6D2D2017D3102E62C9701EF659D31123A", - "adv_salt": "2B55", - "plaintext": "FE39093AFFE36BCF5A70E64B118385C2F23C5E24", - "ciphertext": "3378DD86C535A6A57F46BA3337BA3FAA4143B40E", - "metadata_key_hmac": "D54EA66B4B72E8B1DF134AC6DF84885732EC3E53D3B1897AC22387E90C6CF937" - }, - { - "key_seed": "29390F48881DAC83417F7E93BAA98F6208AA9BC843C4DF2770DD0A7717322524", - "ldt_key": "C7B6C721BC055963A631676239AAE3DC4B56355D93A79EF20DBBE08F2DB23632CEEAE5B3AB86663221773D2F9CC2652E7633B27D94680585DFE588A8BF0CDB22", - "hmac_key": "BD74E00EFD9CE8DBE2AF8C33108BB6E83538BC93E87889B46173D3DD66FF19A2", - "adv_salt": "166D", - "plaintext": "F165CFCD52972DA6EE83086FA4C2573A8EE36905A6C6F5", - "ciphertext": "7A23C2430565E17ACA32F8506E67E6619D4F2B5BC546D9", - "metadata_key_hmac": "B7CE26107122B7EC595FB52B8E54A9261A05E4BF676D15A7F4464E8F8867D255" - }, - { - "key_seed": "817E52C029A497D13CE38EFE8521AC3AEDDEBF825300E35861001595FEE5E728", - "ldt_key": "47808ACA04AC4AF0DA650DE8B7D345F0B5CA8D779552ACCECE1BE594DD28A11BBD2EDAF4CD17A3D311DDBF4AA30040C576793A78EA4CC0CE2C5169FA48414464", - "hmac_key": "7D2593072EC564982C10773DE9617FA320380B0F35380E330E00236E83205AB2", - "adv_salt": "B16E", - "plaintext": "979F741F6384DBD02E30EB848AF58CAC0E825E6ED5BE670E08625B049D6A", - "ciphertext": "6550B23E88ECC6734F22A602592FD6ADEF21D52D40C125E39615D2285AD5", - "metadata_key_hmac": "27A60C66C3B48C98AA7C2A77C7F4D5CB249D0D690A4FEF0E674D709A64B9A3E4" - }, - { - "key_seed": "9CBB82D9821CEA8BCF66833F7E187D3BD7630956FE85AD1D54326B50DBA51F5F", - "ldt_key": "C476A6B0C6D7465F848684657595E88EC794B6C5B19966C8BE00F623D72923B876FFE39B3C798016F5C5B3D6CF90B5F828FABDC78DA7677948A9CD3152CD0DBD", - "hmac_key": "D842D04C078DFDA7103E682CC220AF4A52218EF20E225A20E4610C53241B2730", - "adv_salt": "B6C3", - "plaintext": "B69874B965C6181E34A12E9FDCFC15A44867B570759878A1EF27", - "ciphertext": "F144E75EFF80AD96863BF5A0C478D04425347A6DB670A6B1C2D7", - "metadata_key_hmac": "7CA78DCB2E193F1F9B0E104A04D8FAD188CE31A5E6EC52BF274A9F38A01D72C5" - }, - { - "key_seed": "59B092A37A79B0D1A427020B5751AEFBB19122ABB2DC451B54575012CC18E781", - "ldt_key": "4737ABD41647EFC55B97BE5C0E992D6C3D0D9A0444F09B816F70C599197C7A07E6DF7AB0AB790F250D2EB1B626B6E522A83BFAB38E96ADE6582CA90E556F7853", - "hmac_key": "CFA5F64B00040C786FFFABE5B634881A7E6D9957C1097F99522EEC4FF3B71186", - "adv_salt": "9F65", - "plaintext": "41C098BB1D6420043908C638126CD7135F", - "ciphertext": "A8DA29B3072AE8C85640C7CD51FD6D5928", - "metadata_key_hmac": "5F4A8B2F5DBBEC14CA0AF02F9D0C0B1BE967F4A8071F5F14C18131BC0AB3C583" - }, - { - "key_seed": "22AC202ED8FE097C8825CA079D0DC58A648825FB9250E6D52DAED4CFC015937D", - "ldt_key": "28BAFE4E9174E7BB5056F9AD78308AD4745E49FD3C3CBE89AA670AB31A32A69E443E1AFBB9E497C2344990EA811C68FB62E34E176966B092C0707A5BA353FE89", - "hmac_key": "9A13EC5450F600BDDE1354E11FB54B65236243EEB2D012F2E3E21B909A8725E2", - "adv_salt": "5BFB", - "plaintext": "CFEA46F97492EBA0BC9C41F90B8A36F05EE5376D1BC5121B3146918A", - "ciphertext": "AC5659B294F628673E36B39BCE2A0FDBC7F28FBA2816774D58258A77", - "metadata_key_hmac": "E011B8F87946924EFE20FE9CADFD807709E67CF333742489E666901045A7E294" - }, - { - "key_seed": "0587DDFE9A3C16BBF2B7F3BB29D4972A07FB1AE18387C20B4BC9C256372D97F1", - "ldt_key": "84DB60AD6EE51CBFEBFBFFE655A02C03810758DA394F892DA0817001021B2A9AD332C47DA62D617C23781D5BFFA21095F4F5D7BBF18ACF4CE96B4B51B90AD0D6", - "hmac_key": "5C39C26C51B027C5EB7921D4180CFA58B0BB65089712BE04F8C331149028C75E", - "adv_salt": "F5EB", - "plaintext": "4F5EE0490F73748A075556B53CD3CAC423D9E8B6557954F4974258", - "ciphertext": "8DFD658BB8D7EDF55651487E699760DBB7E0EA26E333AED7B915ED", - "metadata_key_hmac": "D7BE988EA13261746215EEE6A9A4328C04DBDD23FE1BAFB6CBCAD89DC5E31C0D" - }, - { - "key_seed": "353356FBC0A7D3072B95CD06EF161B2E2671A5605ED895204822299DADA077BF", - "ldt_key": "3E93C47CBD43759FE750931CF658E2DD3FE6DF1BA927FA1C1A66D6E96BAF30BE6D4CDF5E1EB41CD797DC514B11379C4D6AD71A2B8E98494B94FEB3810B277908", - "hmac_key": "AD8FA4913963644D7C8F94C8A81CDFEE117F162BF34763F6B689848BBB8DD6E6", - "adv_salt": "6BA1", - "plaintext": "EE4D1B30A0DDB5ED135BB94E5DB5AF6A", - "ciphertext": "484731A93C8B923BB8A53DCA79E4F045", - "metadata_key_hmac": "DC75417B873E665D06E0C1A597BCCF9EBD945FA77918710C9C02AAFABA57FF4A" - }, - { - "key_seed": "7FEDDBABBCA5FBF19085EFDF7FA449069C85BAC7F42CAECB8835EA6001064B2B", - "ldt_key": "B74C33B6186D08E721B87B613E0C918CD42DC3D2462EDA5ACC6EE1BA393DA2CA381C696575E6075AACF233544A05AC4D8A344D62AE29FE5699B909D1474AB1E8", - "hmac_key": "4410A7C075922CE821A7E32EB73F2594BECE696507EC3B31DE9A784685A41548", - "adv_salt": "CC8B", - "plaintext": "B90E090048412D9AD15738C13B42DB98E431A752278750", - "ciphertext": "4E3757534A4F9CF015564178C2C757A37D78B1299E8C3D", - "metadata_key_hmac": "4A09CE5BC6926AC6058095E3D8CF9E027CF3D34B50632BC22BFDFA291DEA5F22" - }, - { - "key_seed": "7367DC37CC19142159373804965C43E9CA28AE843DBF542F2273EC8352CD4090", - "ldt_key": "3DE9CE878554D735593D98BFC7E6AA0CF8077AE0C79BF9D4D218D07595F3A3FEC332FE9100F95D7543DAF0DC9B48F931FA698ED2AC3D5D16D15F78CBC9BC61D6", - "hmac_key": "A23D66ABFD8EABE9660635249025DAD4D76E7D3B9EE76B6E03FE7383B8B2FE47", - "adv_salt": "CCF7", - "plaintext": "604310E1BA7E0921F0741CE25A0B3BC630822BEF8FA95D282A2B49", - "ciphertext": "94877AE1D36AB555C94B0DE4C12E6D07DC576302F5A4605C90F150", - "metadata_key_hmac": "1C0B94FE2B78CDDE0CFCD5C52FAC37288CC8F31D6502F0F0A8CC9B46136FB618" - }, - { - "key_seed": "82D6B3CC208096CDA562F2A197EB0AF48526AA537FE696E7A5906FEB6A9D9BAE", - "ldt_key": "D76C5731D20F46709B4623DA5176A18362D4FBF31D0050209ACA5EC226495065734A1E5E4CB7279B9164736A68758154569AF342361BE36472B91BCD6357F636", - "hmac_key": "5B358CB9094F9A3AACC942A6ACD8B429ECB9CA9806245A53F20FD90C1DD7AF86", - "adv_salt": "ECB9", - "plaintext": "B614CCF667685C509C1E6F6007CE910ED3F4C10489B78981", - "ciphertext": "4087ED2E3DAA9CA529578A8D9BF7B82801B6C2F9993F9E01", - "metadata_key_hmac": "D3F2E705C732A1A40F561AE5CA652CE90FFD57F096BD0DD8693DE60E430A3850" - }, - { - "key_seed": "C4AAF69D55BCC6809BA8047E46AE2951F9F9D1C2DA4D2EDB4497EE422449656B", - "ldt_key": "0DBE3FED8D595946E396085D37627D1DF502C62837C19E0C637378D7B113FE973039301AEDD1ADB5826454759C253194ECAE2F51AF658E24FF53B6DC0CAEBE8C", - "hmac_key": "1BA4C65445037AE9BA3E0B4DF02DC7284444724F01F046D1D27B55A373A26689", - "adv_salt": "BC66", - "plaintext": "02C2762DCD029C77B3680528879E928F2F", - "ciphertext": "421D0B4D61BA0E851D8C988ADDC1F7106F", - "metadata_key_hmac": "D41AC03BD3757F5722EA9178CB4A5F159987FDF4C8ECCA81019AF42430215704" - }, - { - "key_seed": "EF6E76A452714F136B4BCA5E451532130AC5D54BE0F3E92BA400E822B5D5F663", - "ldt_key": "DC186901F3A8C80EACAF342B9738322B2DA0DAC2A9D120FBE5A5EA23B3CDA8DC84B169BF555A1FF97DF8401102A5A158B09A1C6D69736481D5F346749C64ABFF", - "hmac_key": "5BBB6C5A93CA93063E386F8DD215568F2F0D9F0204FE379C1640463330B4772F", - "adv_salt": "5AD2", - "plaintext": "1A4A986327D60F6DEA79523C538B8EB65ED0B98C88F213", - "ciphertext": "D7A1014E0F028131D1B68915AFFD4D32654B3F58E6B4A9", - "metadata_key_hmac": "994181ECDCFEA4919BEE1A1653F5A28B0B5EB6A08428999608C8F8CDCF273AD1" - }, - { - "key_seed": "1FD6A210A15F7BB8F621BB455209783C7C3F97ED76091B5B73128A3DA89721D0", - "ldt_key": "B71CD649F8E878F541E26DFC7E9D2A268ADD1840CCBCF18D0D6D490C3C8DA1F1D8D757CE85AF2329A0FF6F00857637950A8D6CB150185DFACC6E7947AAF40565", - "hmac_key": "20066BCBA3ED8B17A8196406F9CA0321FF4E36D5869CEF40D5162641AD680D43", - "adv_salt": "B019", - "plaintext": "FC3A04D7DBE4298E89F2C55B9152C354DF3EFAB17D", - "ciphertext": "CAE8DBBD312ED58B62F3B0B5F2C3766C979B73F5AD", - "metadata_key_hmac": "5BEFB5B32828A6040761FED70437A20666E73E438CC6DBD2E2260EA08C40FA82" - }, - { - "key_seed": "40796B04A81037C8DF0A7EECFF2A564D86918948AEF73824039E0502DFF24B9F", - "ldt_key": "D45D2B372108DA4BAFD1DB4AFA1E2A072D265A132AF2FAB10BB5DEF4923195299B21513BAAE0787AEF897DC6C4E3DC834E8B5B36650AF054724343B4A212D905", - "hmac_key": "02328122714079A49DD34A85287A93A70700DAECD16CC2EC334B35F92939FDA7", - "adv_salt": "1C7E", - "plaintext": "A7AC225B57D56BC713194CADE4C14DEC", - "ciphertext": "A09BC1E6E33B6D94DA83DC15609EF00F", - "metadata_key_hmac": "D8FBB71457FA8BB077DE75736BE088389F6937EEDEC83FDB915DE02AB6B73B1D" - }, - { - "key_seed": "9266A6AF4A9BAC16EDE23A0991ABCF1BCBFD207B0C75EDCDC17026AE870E5AD7", - "ldt_key": "202D04E5717E093F366325B2D53C7099A21780208C164819B53A7408688F6DE1FA0FA9911A30CDD9C8DA9FD0D250D66D501AB085671FD3CEB49ACECC4F3FC574", - "hmac_key": "63C4A734233194AD20BA4B709A866B53FD8385A1109B1874B47C55D8A199026E", - "adv_salt": "B230", - "plaintext": "CA1EDF7C35B80DEADAA7F1FEF5D1E8B80B62912732", - "ciphertext": "E3E5FE59F681508AE5E89D4B4CFC0E1E2A76E864D7", - "metadata_key_hmac": "42D6811C114796FA032AD60EF690A55243BDC9F47BC033969C99A713CC8D6F6B" - }, - { - "key_seed": "E9D71D9263432A4979FB8A909EC1EEDF8C5263BFAD9D0AB708CABACCE4BEF1A6", - "ldt_key": "D41DF680DB01DBEA500644D4EDAA1BFB2FD9C1E5F09CFC50B0669F9290EDAA7234AED1D2832E6A243DB22346829DB191B1E0B106573708E77ABED4EB2B937CF8", - "hmac_key": "9D067E24A5FFA79EB0651264DFBD2C16DF96139DEE2F4182DD93BEA3B43478AB", - "adv_salt": "17A7", - "plaintext": "D6418E0E2C7687F5F4AA42CA2A0702153B9F642494", - "ciphertext": "14486CE8E4401C765E9404A76A362C76E8D91AB48D", - "metadata_key_hmac": "93CBA7F6D5C459FF4263AC2E64ED865836A8897C11F20A09F748F39320A78ACC" - }, - { - "key_seed": "182A610DB1B47A0E4FFA62DD17BFB4EDFD12C746B400404E3B08DC381970049A", - "ldt_key": "8A78B7701B7A0D700133A7DBFC5F887CCAD49BCAB67C896E32202C7DBE775215C6099EE9B0866DED3FA587937FA94F95B35EC100B42F749B8C7768264B00C586", - "hmac_key": "8C073133C495EBCFDE4A2F112531D9370DC1B29CBA2CDEC96ECDB9C3F90D4965", - "adv_salt": "E2A1", - "plaintext": "A27CEADE8B0B5F62644EC0D70DDCA0C826FEED598510F8", - "ciphertext": "3041284AF4D331E864DA9C517D4FFC04290281F736FFC4", - "metadata_key_hmac": "243CFC7A484FFB6862B69538B2CBCB1E90EDE91E594D8C25D9ED548B31D9F549" - }, - { - "key_seed": "023B2309325EA8A81184CD8B43D24D43C24B09BC7C7736284849E688FB93AD40", - "ldt_key": "2B6EE387E86FBBB54E3F1AE88C0CD531806C7348E50551F90E857B5180E773027EB995378DB02C0F36F3F03B0F861E68D6B04793BAFD3C8477F9AFFB05701D4D", - "hmac_key": "1B91A69467B552C5F7504B2DCD0788F29AB7F7FE6112D96B529E5603C1F0A65D", - "adv_salt": "8302", - "plaintext": "168ABCFA4543F826FD99B738E0DF53F6100301E4FDE4760F37", - "ciphertext": "DBB976C88768AFCFF70E249EEC7D3F804EB57101C2CD0CB355", - "metadata_key_hmac": "243054355CC2D631349C6CF5451BAB3D03639A6DA36B26CA8682932DF5BE6F1B" - }, - { - "key_seed": "C2608A5ACB87C16BFAF8F2AE92088076B65AA5987EC3637592B8839F38C9DDCC", - "ldt_key": "056EBDCD4E682DE1FA9C43BDA3F8D715D0B1ACE4295C2AF455745647420618416FC7FB0C7D86C55AA395740829080A91A45FD9EC82061F61C8D810C31638F300", - "hmac_key": "6FB4476757DBFFACF34854BD57FC6414D459951B6B56D15644806DA8DC0FEA3F", - "adv_salt": "D93E", - "plaintext": "A17DAE592FBB6C3DF1BAF7D14668F1EBB6DA919F67696E45B1C73F553BF4", - "ciphertext": "75C758D0640454385A60888556A185012B5923817D0524B5800EE15642E2", - "metadata_key_hmac": "56203005CC1F8542A56AB79D6C4DA6AE7C666D16331EB05D2CF1DF6DCF3899BB" - }, - { - "key_seed": "EC99415836A71CD018FE253D06936A592CCD14FEE0ACC78057CF245CBD9BF69A", - "ldt_key": "29486562867DFAA482CFE845052DD28B3034B0522CCC6A0883B286EC41F52C6388FE7EF143962A8630604D0E4164566E920ADFC2AD950B281F9277FC592E99E5", - "hmac_key": "9BA951CBADA3DFBC74EEA42E622C6CCC862A64C71B3825B7CE266D87213668D2", - "adv_salt": "6365", - "plaintext": "9823CFB0C109E44CC231D89A8EBF12B6FF6A03D579", - "ciphertext": "A81B2F8688C563E0F918CE57BE04BAB25CBE6E3B08", - "metadata_key_hmac": "C98A745B649061123E20AD2DA609683FC9BC67AD694CDF8856C23D22DE6C6373" - }, - { - "key_seed": "4A8000E1FF9A8DFDB1EF0A04D6E9523912E0E5A0FD90F4B8ACE2712B4D693944", - "ldt_key": "B19BEFF07C483C25B386EAB6C22C75AABEC196B16171D0ABC561610F2B9030F6F446236437D1E4F8E398A4DD1F08F01EB58A229AAAFC0D11F1F6FE5197BCEEC3", - "hmac_key": "C74FDA2826E06259EB44F16479DFBDDBE5294AB6C8208CC0EEA1F6AC889F105C", - "adv_salt": "8E59", - "plaintext": "B15F269256F5D40F8E2ED220AD6B8DFBCBCA7946A313C7B15FCB250FFA7B", - "ciphertext": "A520E9096C35B5AF65EA0288E4D9B5E0DC59E790D94CFBF3B88BAD4AE108", - "metadata_key_hmac": "9C25CF530ADB0054D44F4BD955050746CB7E937F3CD3104AAC530152973002D3" - }, - { - "key_seed": "3DC8E89B729D04C912D224CFAEE6BA147FF4EB46665F2F68262DC42665BB6546", - "ldt_key": "5CB7DD6AB6443B38370CCB3FC5A618377A9917F725FF8C9B76239CA9C6E376054BE402BBDCEF6BB83F3DA8ED51F606D89C7DF6DA85E954D949689738E052B0DF", - "hmac_key": "3581EB8A202E79901AF0BCAE667AF7170F027927BA27668427EFC2C6024117EC", - "adv_salt": "D335", - "plaintext": "D4CA99804BC9A910004201C8B7590B95038C17", - "ciphertext": "BA09BD3FC063C81E3F72277458A7618EE900D1", - "metadata_key_hmac": "AB1ED3B3518AFC23B788549F5BC0B1FD6A201E97E278F817EA329A6BAB0309CC" - }, - { - "key_seed": "0006CF5225E174EF822A30AB0529B69C108475DDBAA1AF43A44BF51C5D5DFA8B", - "ldt_key": "D92833285EC8FDDD39EA543E270852CF1DFEF74AD515E031D043167404A9A5C5C76210183496CE26B57AA958F5212C04CF316C5B124BA2CEE19FDCFB3A4E6F65", - "hmac_key": "CD5956A898365B6414ACB0D638EBDA608CD04FA59FDDC3A7CEAB493D43EE303E", - "adv_salt": "21F9", - "plaintext": "D8CA79DB9522E28903F1776A9671084425A33435318796B61720A5", - "ciphertext": "9F3CBAE4EB6F96B2EAB8435D9DDBEAB355EFF423AD14E928D55EDD", - "metadata_key_hmac": "4CB0388CE318A093938482D9708182DE20CDB1F501B9343C8FE24B2C2ABDBB0F" - }, - { - "key_seed": "A35C0F85F77FE542D4DA5BAAA7E4C192E43F2B4769C9CF77C3BFE43610C31A89", - "ldt_key": "820DACB1C131D804BB7EB5F88F9C4424F6DDC2BEC47822DB14444AD7D9456264028FF618932076C1B127B221DE4BD85509F5B16C66AC070C113E94CB0C810C56", - "hmac_key": "94A5415308D1A6CF92901CC7169A16DF66C35DC04E79728F13EF8DD60AAAA97A", - "adv_salt": "75C0", - "plaintext": "97C8F490FFD81E751E58D14EE57320F87441CDBE7AE1E7F704", - "ciphertext": "778047CF7A20B43156AFDF2F6DB68A9354483CAB803E263473", - "metadata_key_hmac": "5F28CBB5A8CAF83F3C859C430162F1007E9E122FF3FDCBE1A5E9C7D7345E68AF" - }, - { - "key_seed": "648D28EC0F235C056E19C50560E20C1C9153F1B1FD575ECBE61EC63C02946D48", - "ldt_key": "9F97C570D9EF9654996F39C42004E87A0DC1AB778FB80A6464018F809BA3C22CBB31C718F60CF337B4F3EF00A225E7F79266030EAB256718287A1375839420A1", - "hmac_key": "77D747DED1BDAE060B54AB5C14B2C505FBC1628ECDBC8A5403041EAB31B8CA35", - "adv_salt": "C47E", - "plaintext": "FB7AA8BFDEB67973132225B6628E590F06507F3224", - "ciphertext": "82C3DB57DDC5A82132950666E76FAFDE78915C525D", - "metadata_key_hmac": "76F3737220512662CBC506645D6353FCF625CB28D7F4749FEA2DAC66AFDBB4B6" - }, - { - "key_seed": "AB266006BA27C9B8BDBC348E2F233458A47E1D081E2D8A7F75E1266BC3194A71", - "ldt_key": "FF0C1D83127BD01BDCA768A290EE460AF5AB7194713A8416C8F2B71654018174336F6947B3B65278D99B1A84F1FCF52EDCF69D54778F143EEF8039488D1E5444", - "hmac_key": "F0EBA62332D70ED32904E006ECD15023C74A2B31C6DD97FD71FAB9864B1254D1", - "adv_salt": "C6BA", - "plaintext": "C3D3FCEA6BB15407718A79DDB6E250C3AB1E29874C9666C9B9", - "ciphertext": "2ABA6882B6E4C2DC04DDA8837AE7526E4AC32182F245C5EF31", - "metadata_key_hmac": "0856FCC0CF22234B88CF87A3B28F9637B3F3021D6832ACE0831551201E12A18C" - }, - { - "key_seed": "39422A1CB95CF979E27D915BEC424576212CFCB22478ED1DF6748D61001AC677", - "ldt_key": "04CA78ADF1E2A09A1C4DB8B3DABB5614DF1171A1908D1572AF42BAF252DC01DB76075F21F9DF2B2B1CC217980EEE430A5D2B699C34473D9B1BBCFFD21187F673", - "hmac_key": "24416CCC591932474B8CE26593952FC0B39842DA2C2D4496A24C7C18CBA078CA", - "adv_salt": "BEFE", - "plaintext": "992519171843560D593A00650010B419", - "ciphertext": "9289780CBCAD21A63B1331F4211B6CFD", - "metadata_key_hmac": "9C3383C57A759CFCEE5FDE6CE412ECDBB2F4B991EADCA608EE3D428B37D7A61D" - }, - { - "key_seed": "AEDC72F40D1713CFEFC695094277BF4F09CD3700266DD5044B9AD4A30A4A7075", - "ldt_key": "B95B709E61493E41793C2BFB7352DFA905418AD306EA8D9EDE3CC7E0D751D91F430CF8821F8FFD291275CCF9ED309F914B74204608495CC9A011DFB04011846B", - "hmac_key": "7948CE0D76CA3A9885F14C3350111853030D260482D0A17EE9F5CF950E3FA7D0", - "adv_salt": "93E9", - "plaintext": "2CCF403EFC2BBF63CE6713CED63E5C722658B211", - "ciphertext": "DA024ACF0DBF96DD958A2B899556F7ED522807AF", - "metadata_key_hmac": "172D657C3C093D1171968D917EE56A9F18709C21E04B4864B5933BD231E1B24B" - }, - { - "key_seed": "55F79B5A7A22E805336CC8F2910BB291FEAD07A7B85D88CF1101E652B889A578", - "ldt_key": "CA54FA3548DBCEF6807EFA9804CA53B382EA05CDBB7334846810481FE9F327639CD561844165EF1047DEA7E9AB90C7F92F4ABBE01091DEADF71B02B443868CF3", - "hmac_key": "44691723E9B6B50F4E5D05F8214864E7AFD29E9CDC8A29B593FB38D1146D86A9", - "adv_salt": "731C", - "plaintext": "7AB0D04C39CD376574505C3CDACE42FBAC93D00D9E63E918AE", - "ciphertext": "A1F451AE86A971B40C3EBBB301E1EC142B2B116C1BB5A7B4D9", - "metadata_key_hmac": "8DE18D0F719077ED04E28F8C83B6AC7116CD9FDC76AEC4B127092A17B25F7A35" - }, - { - "key_seed": "E0E8F2C704B79101C4AE1AA6EA66DDFE3595442C77FAB77B08B5702796B8C80E", - "ldt_key": "4C3AB6C363C96574DE798F9297CAD532E2E4708ADE76D74465E09322FC9FC3A6817AC940A10ED4D0CF14E9D3435932AFDB7ED0526AE0BEBF47C81456CA9A6CD8", - "hmac_key": "C54A736A79A344E66E7B83F95FE44F858E7AC2C2E2AF79F9C346CE0E481E0AD6", - "adv_salt": "82AE", - "plaintext": "A9184787EEE39C0D471DE8EEEA9E1E7BDA0DDB37", - "ciphertext": "97F5675D53AF0BFAC6A58F6114C9DDFCE3DB0608", - "metadata_key_hmac": "1B6ADF08B7DF306C346A74AA74390BAE8DD23BC224EADFAC50B35182949D305A" - }, - { - "key_seed": "3E045EC0E569AB8656C45B59F512E5B03DAD427D750F98DC6C4C4509B339A959", - "ldt_key": "6A5466A4C6A174D8B35DF32C2A08BDE5D4C5C9B1E779BD803FCE50FE190D82C327B50481B4E62D2C3902BEE106C6EE1946EA32B022B6B6557823270BC6AFBF38", - "hmac_key": "0FB3C7F3100261DA4420D5EC5B94C3855C82A7371D8A8F75C7E921CBA1154D81", - "adv_salt": "121A", - "plaintext": "40DB07B6329E6EFC10B79A004C8C544666FA13A81C96B37343", - "ciphertext": "CF082BA8DC959FED33D304CB5EC66B028329BFB3B2CA53184A", - "metadata_key_hmac": "E469FA33B76547861B26F80FB68FE60251E904F5997686A42C2ABE6E45AC6A7A" - }, - { - "key_seed": "807DC7E3EBEF3B2797636D316401D339909EC63C23F9AF142BE19D7A5D4E9B31", - "ldt_key": "07709D1ADC769DA662876C45C89477D941B9C706CB11CB1FFB789BB3FA9410398321DC404CDE4CCE10801570CF3D83C2E88D5E8E12E5694CEFBAF6D67E9AAFAB", - "hmac_key": "23C7EB3B019361D502337C2035C571ABF7BCFF36EC2FA0B1B14CE816A6874E3E", - "adv_salt": "9E75", - "plaintext": "FAD1DE90363C6C1413EA1B1461CCC43F", - "ciphertext": "28EF13E59A2DAD573B0A1B0B927DF629", - "metadata_key_hmac": "8475DBA0DD7E6FFD7A1D9D0214B4A8EC4004BD7770422F37E68B2044569E1AD3" - }, - { - "key_seed": "A62BE1A3BBDB99C67A9E0B9CCBDE92D581BB491A9332DFDE3A83D4DC8C821596", - "ldt_key": "9BEEF268C80A80BBD8B5151CB8BC6DBAC22E543BF65293E49864461AF501C9DBC56B84F3DC3495409D6D2D0F84329DB2A4A3F95F2902F46DCBC4D77FDCAB022B", - "hmac_key": "BE69A6D4391A1B7647D2A261F6FD19C807C03D7E873DC18ECA6BF7D7571A3881", - "adv_salt": "DA0B", - "plaintext": "C1F1DC66329A41743732DA0B5EC6C87771168427E60B", - "ciphertext": "65D9A77973EC29D6B3BC3E4A84E388DBEC013A63B8A3", - "metadata_key_hmac": "047094B27579869C1D81EA857627622B2AC6751E4E4F708FFBDAA844E34231C3" - }, - { - "key_seed": "8225BC81B6A95E41A5FA6BE7BCDC4013C15B9F3E673EA91C99E4B8F9F9641F18", - "ldt_key": "88FCB6677A3C2565C40AB907496A5BD8DCB60195D4D5947826EFBA2E4407A2FAAB56E6ECB710ED440721BDA2E8CEA571AE28DFDF2D8AD0A0971BC21A853F948A", - "hmac_key": "F54EFD7864BF2FB87EDAAC78B187A9717AA7CE43BD0BDF0D6D83315D7D3CBD96", - "adv_salt": "86C0", - "plaintext": "8101E73DE0C94BA78E37CD8EA9CC6D0B3E52221166F1F3", - "ciphertext": "E5EC5C5A5BE3ACF76751F6E5C45910A3FBBF0A1039A8C3", - "metadata_key_hmac": "FD9FD785E938AC6719CCEA7AA30AB6B0AD34976AD53E902CDC9362F9DF978E9D" - }, - { - "key_seed": "AE4BE66731EEC0ED59CC7F8E6A616D991326AAD5461806D9D8DDCC673FB1E74E", - "ldt_key": "7BBB3F3BB47613EAED7AF01630013423FB8FA2F0BCE3266D4C1C3358230B99FB5CC8C09D6CFDC712EEC9A3F8F2FF2915B0383B8CD2C21348C626F057F4F315AA", - "hmac_key": "8D6B94B9BD6DFE59C525F196ACEA419344A02954B274C0E4CEE516E5123B1E46", - "adv_salt": "C968", - "plaintext": "6BE1C9FD4B45E62BF3F3CBCF5A281ED900B1EF002755F201CF524F", - "ciphertext": "3CF6133D11238E9139329337EEED7E9C529A6D46C3506F7384295A", - "metadata_key_hmac": "73EDA04796A798B1D0A401560F8F569F1D8FCFAB1D1E4AADC404C02108D5C9FC" - }, - { - "key_seed": "60763945AEC69521699FB1393024D7A4CA97FA63AAAC48B5507158909822B49C", - "ldt_key": "4624393C688256207C58D4EDF09234DD60754A7C11C5B6443BCA04CCA8194B7F28C02BB1A03CB0D51B8D57F53EA8A2DE2E2117C89E52B4B550EFE82437D32054", - "hmac_key": "7CF03F2124D4062F65D1F413E9A02CF91FD1AC9F4CEBFC2BCCE079EB3EBC902A", - "adv_salt": "78E7", - "plaintext": "0B9DC49C436D188F5E02A2F7EF72AA9E057197FBAAD81156DE40", - "ciphertext": "71C56A1CA97DEB8438D2BE29BA27C9D5AAB05810670EDF9B8FA3", - "metadata_key_hmac": "4DDEFEE27C077AED36492E7E9B490F81BBF921851BDD50E906F5E50E3538BBFB" - }, - { - "key_seed": "ACB1D851F960017B5DCD5D2AEE38CE6221D22A2070592A7E1F2D56125DDEBE4D", - "ldt_key": "00B3A0B7A6017A6D4711257AEFD809A61A497F56D9BE053412589B284B3F8780E55D6ED711A10B6AF63CCEB8C493D59128460894B91CC07EAED4388EEDB90E4E", - "hmac_key": "F61FEA59CBE3E50C7570918B91C0C79C83D6D8B49F4C722A1A2DAAB7FEF93B22", - "adv_salt": "DB05", - "plaintext": "FBF9190FD2C1C63ED84BE2BDD4DA1878DCC922BCDC78478E25947344E58E", - "ciphertext": "BFFE6DE27A2648CCE6635A8DA00A559D7451F44BC1F92F10F3B55293189A", - "metadata_key_hmac": "708591407C24D5E37ACFB67A85E216D889FC6328A8371EDE4A48D6ACE2D38AA0" - }, - { - "key_seed": "5892D24DE35450EFBDE91AB2B899337DC0FEB3E4E08F12AEFC21290C3BB0F5D1", - "ldt_key": "16B5A4776C7EB3FB15C122FF3C441B1216E8D81863D8DC22FFCB1606E9CB90FFB01205BCEFB026ABB6637DFE593AFA3B4DE8E5F67D7FCE8F7845C50EA73FCA10", - "hmac_key": "6B87C3F28E0B837A3642D3EA89A5AC66B6406FC6061B2A1230A6957E573F62BC", - "adv_salt": "7E5F", - "plaintext": "C70CFC105673CC008117C84C3B0B8B6B", - "ciphertext": "E7143E3EB9B085FE6CD8830C1AA85825", - "metadata_key_hmac": "03119A6B609DCC4A1A0671558F26408776CEF78962E84E0C264BDF71EF8A4C45" - }, - { - "key_seed": "FCB53B88C29480D31C61C9A26C1FDBFB90F0C1E482EAF41CDCFC46C106D7FA92", - "ldt_key": "90740E785F31C6FD23F30EEF5A1BFB0DE75A1EE6D88CAD8FF84154132B6E41659F1CE14B28FBD09B671D2A2F789D33B94F3DE2C945A032EF8FD47A52B53A50C5", - "hmac_key": "F66E97715C702A60245C1E091082BCA6424B309C34D0A0267FCF41B2DDE10EAC", - "adv_salt": "F66B", - "plaintext": "024FADB6EA3D3841BADDA0030BAE72906B5E8E9A8B830CBC", - "ciphertext": "71A33F0C9E407FF1C68E25CA56F4D37B34EF1CF9DA2A05D7", - "metadata_key_hmac": "BE3C7A90CC50BA0426903025ECB40F5A1CB860C2F33D94847A5EA122AA919B5D" - }, - { - "key_seed": "A3DE67DAD089DBEAA66B19E86D2FEA6687B14248838D5770243FB598F3C4A7E3", - "ldt_key": "3603B2E7AA69754C0B8D384EF0B23E6237556ED876310BAD17E1FD2C8F65B1AEBFC6769FB9FABC1EF97808591B9EA3E9A1720611F0620979ED3DDF1235E842D6", - "hmac_key": "7999C39246548C92251A110796666EE1889F756DB0EC6DF6B49D5A72699BDFD6", - "adv_salt": "337E", - "plaintext": "41D76111DD0F330918F3AB4E84B51EB9A2663C7D6F55B85DF58B2CA7", - "ciphertext": "72DF51254FFD1950A98ADA8075F6A93C442F1AD8CA7CF6C78F5CF237", - "metadata_key_hmac": "73442151CD271EC8795096EB3272ADFE33D86A774283D9BF209DC291C8327201" - }, - { - "key_seed": "FC47F82D1CFDC44C45DBFD8B50FEE2550FB10F4C501A43F37F975F375169DC46", - "ldt_key": "8E92BA0192BF1CF8A7526A868AB03DF7AB60460C90890E9E3D5356978D7718249370906D430B548CDDE38CC79CC8A433997B656113D5C1449E5C92996B181ED2", - "hmac_key": "31B759712241DCD1B9BAA2932AE5E09D65FC7A8F61449E54E9732677D03238E5", - "adv_salt": "FD7F", - "plaintext": "0D83E137CA7BC4200B5158193B54FD0AD2EEE5A15A61F58E5402F326E30A", - "ciphertext": "656BB517EEBE4F2B48600DB4FBACFD5B188129BB288C34518A2CC82BDD42", - "metadata_key_hmac": "6120ADA9ED2B4C9FEDC2DB990924C33AAC3410E41ED41487C1CD7E52059434A2" - }, - { - "key_seed": "75CDD577C4755E5A0740E8465AD380F178DBE0D64C14FBA56AEADCC204520F33", - "ldt_key": "68760B9FB6C651B1B4FA00EA2DD39FFECE7918B16C37C8E1AED39144178DFECD864450AE55F4F43C6EECF3354AD990A01802B2F16CCD3BCA5B2FF5ECE5D1F889", - "hmac_key": "8363C9EC9B08C3F5A36F81FBE6355B3BEAD57FDF534BC78A241D8D5EE09C0A55", - "adv_salt": "6639", - "plaintext": "58B1E6FDC85A719780CE6E55BAA86B69EBD383A9BEF3A128CB", - "ciphertext": "424FDA5EF7C74F2CCA242C4ED06CDF7F018C5E66C7D0D0636F", - "metadata_key_hmac": "18EF8AC0ED8CE9CCE1172BD4AED6236F0A4E4F1EE639326BB4D6B4E83512F279" - }, - { - "key_seed": "964C1500301CDCC623F5CD0B1D7EC3D766A6409AD2D7C2380D15CD3D3A59C081", - "ldt_key": "0173131036E303C6BA39AB157529683888D4A3483ADC6C593A96F73469B4964EBAE07F195DE49C14453C962F197B6F4D302D0D9DCEF98A20B102FA99945CAD5F", - "hmac_key": "B7DA1265038925CDDB1C66C34F58B4ECDE531E4DEF61FED637877830FCD67B0B", - "adv_salt": "2D05", - "plaintext": "558A23FDA9CDFA4F8C4DA733C18FFD3350", - "ciphertext": "29ED3F11E844F8C5159597DD712FA7F005", - "metadata_key_hmac": "B914542CF3E6EDF434B1937A4EC11D792A487E0A2A2407D331262ACCDF23AB56" - }, - { - "key_seed": "C98EA0AD4508C49C13886FC1F64FC531BF700FFD4643D1871AF50073DB70F7DC", - "ldt_key": "D0E28992554ED4D20875D2F18B3B0B6A3980C257CEF7C30ECF33DA9ABBA2184A2C6AE292D1CD7DB546D10B72837949B7AA066FF2AD20D341BDE483C7BBCD9333", - "hmac_key": "B4BCDAB34821AEBF3E5F62D64B89DE9B6EFDE9DA321BF8A7282E9BE1B2BF7487", - "adv_salt": "2C2D", - "plaintext": "6568B8EB33EE307B2D17E988F070425E433012FD2D6926", - "ciphertext": "C0D072E782E8657D4D1A3C94429555E05A96E508E1A724", - "metadata_key_hmac": "C575DAE69E903B641D0F065970B90481835F080D2356AD31F90851D0CC60F1C8" - }, - { - "key_seed": "5068BA6E60D27009DBCF17FBBD2B4FB16F8E39BE8E08EC16655691C25791FEB4", - "ldt_key": "B574914DEC464D83F7FCEC28772C1079D7725E3E50B7CAD4B848908F0DB2F0C99DC89540F2DBE75BF010EA3251737EFDE7E673CCE08AA14273D50F3C0430B8F5", - "hmac_key": "70DB70FE8F8DDCD7513415F04E56FFEF713AE86B42A38AA324EA47F220D14E6B", - "adv_salt": "9E90", - "plaintext": "E725C15924229E8D3CB7A8A8B25BFF978A0887EC398CE0869CBDCD1E", - "ciphertext": "A168E685BE69D7A404743421580C99F3FBF3516D5605030BBC2B398F", - "metadata_key_hmac": "A7D3C12100FD3D35426999301D916FE8802BD87624224C6246DF64CEF1813E34" - }, - { - "key_seed": "5C79EDCACA1D21B0994A45DAE06542883BCA0D8C04421A3809B11BEDA8DFCD54", - "ldt_key": "B786B17A1C9D89100AE1A4A624B291F60886631C85C5505C15A94754A03235D3D24867D08FAEFFFDC170052398BF78C52372A0670F90266DB4F7FFC866F80215", - "hmac_key": "571C8E8914F72F5A3A2D9B737FD5A090E42C5E1BFC1C9DCAC05635D47F8F31F3", - "adv_salt": "26FE", - "plaintext": "5D510AF1F8CB70050ADDDC19A504E9A8206A", - "ciphertext": "3956DA7AF1485B5CAFA372806FD0F0826A8F", - "metadata_key_hmac": "2AC2100526394E809ADF463BAF1639AF2C0714D5BCBEDDACAD557F8D5AB67638" - }, - { - "key_seed": "EA2BE502D69156253AF8FA64E65C7039AFD10A5F3967E3BCD8803683E5A56DC5", - "ldt_key": "8C0BCD6ABBCCB13DCC92DC2E4E389E394A2C986DD33F1E11CEC0C53F9B4A75E70068820A7934376BE3F1D44320071E0F70A5FC828516088119CC90A59EAC7B46", - "hmac_key": "9CA3FD68708B906D46776F26CC37339E2F8CA5B2047E160C67E28CDC514B457F", - "adv_salt": "1DAF", - "plaintext": "ED01E3CDD1F0084D2B53904147FDD9DC5D8E68F7BFD8CFE5", - "ciphertext": "6735AA07367CF00FB6BBDE6C16CB0772589C64C0321AB78F", - "metadata_key_hmac": "C08A893EADEBC7444220E5B2C00076BEF31F0DF0A85BD3AAA571877247702AFB" - }, - { - "key_seed": "70E69D3D65353E3AAB37DACA6F7E7619FB11AF47EA41F1801D0444B53A1EC877", - "ldt_key": "1D3CEE942FB6ACD5560A203EF5A22D6AC0A9DDFF66C4C6242B1934811E0CAC892247A258945BA677DAFD020AA2DAB8CBCF23B6594B9688F7D29830DA4107B49C", - "hmac_key": "C63FC0CDEA7ECAA9A05D0578DECCA5E3B539B892A44BF81A35665DA69DF46CBC", - "adv_salt": "A596", - "plaintext": "A6AD6912786A8F2413C2B71CF45060A419F3F085CB8F60D3FA20F033E1052E", - "ciphertext": "00A498DAE18DF3447AC0580A0E5D99D88B5002AF00E17D5CBB456BFD437D68", - "metadata_key_hmac": "7BC73A052E356779360968BF5785F5F24E429490C83B140263208D27D544FE16" - }, - { - "key_seed": "95AC44DFECED7848D2BBDE48AE3644C643C159BF5ECBABFA397D6136C5A3BA00", - "ldt_key": "DE4AF5DA6B970F7990845837D06EC746C9833F272771F087E51E58DA39CA0C27EED3DA0F45432C0EC07D10DB1D57AEB0133D3A28D6B34FD9C4299852121C4CF7", - "hmac_key": "4EE27FABCA00B9C4DD92B94838B35F4BA456415F68BA968407D2D38FBBF86AC1", - "adv_salt": "F644", - "plaintext": "62417CDE107AE6A89F15BCF09BC2D56CAD43DBD6C4", - "ciphertext": "964C14893E03762FED52557949E1E67F3E477B7FF2", - "metadata_key_hmac": "EED2F02F9C579E936545F950F56B95CD0C033BF4359C1BD23224A37F3C8A03C6" - }, - { - "key_seed": "9A1F41B0AC6959208C85B084EF2465CED116E845BFB3318BC04D3D4AFF2A91D0", - "ldt_key": "0963F3B352BDAC400086B79A8A07172E1A3D452EA85B0955E0D42923B13A6FB04EE16765FA9B001438CCD7799BD8136DC01476BB4D85BE129EAC71BF32EF0212", - "hmac_key": "A83A584B03BFA85341FF4148DF3F75D044BD4AB561D7F5363261E01DD5D59D0B", - "adv_salt": "716A", - "plaintext": "5BCCD691CC31878A7A557C688952D6641E9D4A8F37913E768C19D73197", - "ciphertext": "DA0845C303EBB48347A7F9C1F854721266C00574A0145EB099548A2C73", - "metadata_key_hmac": "01C60FDA43D3B64CECC9F05D3A58A43C464D4ACFAE8A3DA9161D40D7F94AC494" - }, - { - "key_seed": "53BDBB22732643B193FD8CBAE1783519733E6598912E4AFE84F6E75122C4BF29", - "ldt_key": "80EAF347106A3FCA0A2159854923D4556307FC165F9097EA09CC356A00FB7281168B221318D0C6905AC614275B7E5405691EFF99BA9B751C2DC09155A4EB54CD", - "hmac_key": "F7347BF2808A389CD9E6DA5718AD89187E42F4D113B011B7A783F72814E9F852", - "adv_salt": "20BC", - "plaintext": "15D8E5A032CEE9A426F4BEBE1319B66C88D95B733103188E0313588DCA", - "ciphertext": "86E4B33EB62F4940FEF661B7CE8CB10F4F6FD9826ACC07BE615BB95DB2", - "metadata_key_hmac": "F172FEE4274F485FA6009EBD0D62F17E74E921BAFA79D88899E3078CD5751DB4" - }, - { - "key_seed": "F5ACC9DADD3D04267BCAE2082578EA61C0F6C0267BE7EE187422E194914D5DE3", - "ldt_key": "BB3B714241A446A8DE5CE4B961911BFCD5EA42CEB785BF5FDF47F922107A9204075BA02AD360D5011598E697DBF440FE73BF8146848AEBBC4B5845459ED07EC1", - "hmac_key": "5737EE23F36ABD11975CA37D444409392E033C2E2951EBF569DCBA60EB671DEC", - "adv_salt": "8696", - "plaintext": "6D72189AA757296072E1301D281C2EBF2CDB589E9C7B4E4471E15DF3", - "ciphertext": "51EC36C9BA729F0C2DF4BC0ADA2C3B39359B408DBBE209CBC9EB8B09", - "metadata_key_hmac": "2485051451D77E97559C3E1518AD86F1F4D10DF855151F49DFA4011D774F0115" - }, - { - "key_seed": "6783C15A78CE744C8C11306B938C660B291B59DE3BD36A39DE3DD467657F2FB4", - "ldt_key": "C84D751B752C5AE7399D125D081F1040FE416FF77683DBCB87481543401F8E59FC699BB0DF7CDB600DDEA21AB6B85FA12C8FE28A19C0A5891AB89B5EC8CCF848", - "hmac_key": "B84C3D612329F25B127FE18284510A908F6C1C9ACD5621C1E37AED36652B3398", - "adv_salt": "65C9", - "plaintext": "829452230FEFC15DB039063D2318EEC8A348BB1F", - "ciphertext": "32E19D511199B05E9812089BA1A08FD5986EA2B3", - "metadata_key_hmac": "870D01D40A6B8DCD39A7B638DCA32BC8CF7BC0E90B1641BC0051A7297103C3E6" - }, - { - "key_seed": "68570C52852FC7954F372CC6B4552872AB1509F50A150523F4BA306B4C50D780", - "ldt_key": "CC660A62F836054EE66B265D8764F5359E3417AEB489E164CE7FD1438D77AD27611A861D5C352C1BF96337A3841A7016CA4985BD0D1BAD188EEF30DF5A5E8133", - "hmac_key": "4FA68AB3FBCF3529EF05CB3FEEBCF858D61004269E8F75ECB3262CB34CAB269A", - "adv_salt": "0E8C", - "plaintext": "6F4398291481C729C9ACC626D2A639DB7174", - "ciphertext": "CAD84F3CBCD28CE8AACA5102906E1BE33872", - "metadata_key_hmac": "84BC6A7B827C68E38858E2DE1149E8D939AF989DC7040C4473F7E03ADE429671" - }, - { - "key_seed": "39CE44538302053859A5644BEFDA73B503795FF85A5E05E9C212C8806911A704", - "ldt_key": "1B58BC23C52F71AD309723B9F5D446F8D88194C80B316A9B0C9E9C78644D4771E8BD6DE52550673D95E551212C55F374F842CBBED5A10C32F241EDE1F4266714", - "hmac_key": "5F5790FC03CA669C92AD61A877D5CD7E561DCE1166A62FBE92809240201FA3F2", - "adv_salt": "2AA6", - "plaintext": "2D47FC43E3306D318E3BC1E0560F0E152A5C", - "ciphertext": "732124627DEFCD991E6D42ACCD8A370B2323", - "metadata_key_hmac": "0E8A0E36877C92BB61D8F4F85A7E0D02D973945694455D45132F83B806E8D9B2" - }, - { - "key_seed": "3E1E131C0BE3413B9A98A219CC37B6CFBDE4653F758DA88B106402E3664ED94E", - "ldt_key": "63763C5633719656DDBF4CE8B941B2A7F3CCD952E63AE31AFC7C6985862984D0A427A605B8F58F9AFE0ABF992CAFF2DAEEFF2CDE5D12C29C1783C1D4DA87ED15", - "hmac_key": "CA5BDF30180EFF4970F82A5A8FF23A5C0C8D898FFD0937CB9F100E7F7CC09EB2", - "adv_salt": "0705", - "plaintext": "BEBEFF39A02B34F3B0A31CB9922D8B8967DF58175AD50626", - "ciphertext": "5DDE9DC2E6DE37F90ABAD3B3C12F38C3FD3403963E2B41DD", - "metadata_key_hmac": "461971F6E4AFB07BBA4D854E26125B2A84FF08A2BDEE9DD18A51ECEE070B8979" - }, - { - "key_seed": "0EB58683B5CF94CAE8F55A4EA52179C034A9BB5255E8844F7E81B23F32F6A5A6", - "ldt_key": "D747228FF6B5FCE4C7816F2F5485673CA5948495DE0D0A786FB5AF66EB8231D3A001201129FB9C2E1D59E37AFB706A81B2D273A6AA790E259DDF223697111E11", - "hmac_key": "CF421B245B4927C7C9EC547DBEF2DE0FE60CB8066B4B48FD2D959DBE3BE5B135", - "adv_salt": "46DE", - "plaintext": "9677773693DCBF976497F1D627BBB69BE7B57433A2", - "ciphertext": "A06D673453F8920F82612ABEB9105C5A372EAFD6C6", - "metadata_key_hmac": "1C5B7FC597A70EA96879A4E355A328021517E8A52DB8E05CBEC6C2F210EE0C9A" - }, - { - "key_seed": "703512A357CF1F2341B6EDE889D8307B5422B0387409BD8734267BE3840F33A2", - "ldt_key": "F75C2D1F0FA77227817F27D2BF50646A17E7DC139D0C139402799FCB990B8BEBBB11F9795F010A7407FCF2C5904F84B057099A8E00060A14DC46D27CB0E9B5D6", - "hmac_key": "091213A5ED437436F5CCFBD9708D95FC63103C737D187EA83054B159A9319DF2", - "adv_salt": "6CD6", - "plaintext": "B3A36BAAADAB47EB3A888C886CBE82DE584A860708523A47B7", - "ciphertext": "099F8D46E4FBEC2B2A480C496CFF3BF2E3464D1AC83A8ADA26", - "metadata_key_hmac": "D241EEF767BFD7695F0C7A2A93D847DBE4F79E2FE10A1E427DA5A7A9C81FA171" - }, - { - "key_seed": "BC6D6CC4D0C775448DCA55337BBB16CC950E9BB1F537BF379C9A34153E1FCFBA", - "ldt_key": "7249BA6984ABA597609A304942255EA45D175E7E630F22071D494AD85FD500198572EF1B55061579C8A60042154832B664E9544B284245A7809F7E71634E6862", - "hmac_key": "AF1903DF4D7DD4B6981FAEB7668261DF02856934B72B23E21CB5F32F9940071C", - "adv_salt": "7A5A", - "plaintext": "B453B47C75FE8165ADB9A9C794BC91422955BD62", - "ciphertext": "229642496B0977C5EE5339877EB596B9A6112828", - "metadata_key_hmac": "68E4D0A891F049F151110B0897268607D117CE04E7BE86AD30AA65EDE1B76EBA" - }, - { - "key_seed": "1D1B2722F3CD7184F7B55ABB2D5DE897048A9DB1AE4F53923646074FD651ABD4", - "ldt_key": "8FA39DBC12436D4C22EFB15B8071133F95E30D159B5DF923DCB56556F6C746DB83B5D2E397C27A8407633B6BD97AC5C09844A5F6FE63EE504E59C02153B9E379", - "hmac_key": "49EFB2DD19EC55928BA2DD0055290887EAFB81EC0DC8E58F7F9D0B4FA428223D", - "adv_salt": "890F", - "plaintext": "8D4030A8672074103B63D025CE23EFCC378DE5C31E2BBF147BB69BEDD90FE9", - "ciphertext": "EB90032A5802D2B1B863C1F0504D89C273718C567A47EF02AB1CFE0473DC43", - "metadata_key_hmac": "85255981481522F4AFA9D008A6307D34F52AB38DEB145C60F2836580725137F9" - }, - { - "key_seed": "0EA7BCB5DB506CACD5FA1699E6758E7765383FEF79D153A6CB67C18E3EFB1F97", - "ldt_key": "0EF0AFD7C3329C05A941E5D062B9AE59841C2DA999DCA8999F4BEF8B1B9F8CE51ED9AD7CCB69124E0A85BA2FD9634E928AD96C0B81FB55B0D1D929C8395E2228", - "hmac_key": "F35887CA73B89610DC0CAF6E9C05F925F057FE0151C70F0E89FDE542ACF9F672", - "adv_salt": "E557", - "plaintext": "4213CA09EDCFC3C34DAAF9E1D624DDDF7E34EA55CEF20F57260A", - "ciphertext": "9D8E79B64F10A3763022A5CDBA43008D583B6EAAAC47DF64F429", - "metadata_key_hmac": "DDCDDD499DFD4A909FD66A26D420B627E4F8F9F855D870A774639BD3876FFBA8" - }, - { - "key_seed": "94C0899E4868DC85CDC3DD9CD1A65BB1AB6BB7AF886733E04128528B7A2A465F", - "ldt_key": "0E9E6552B91C674F422EBB10DEE6172341AA1C7878C004883FF24E06C4F90475086AD232704B831A4012E8F60F099D250D53C9507EB232B734CD5246C3D35743", - "hmac_key": "C53A0D4D789182B586D67C128491E049E8A6B70D74ADAC5156DCCA369378CE98", - "adv_salt": "163A", - "plaintext": "FEADAC57B3E1C708290306BA8F657E1520C8280C", - "ciphertext": "3CE4F4228E22C8AB9603DE7D24474DE8A832E1AF", - "metadata_key_hmac": "B8482D5399DC21483CFCDC8B061722DC7E7A25A9EC22BA45891DF6663334A9B7" - }, - { - "key_seed": "F370B420846D05786667A8860FE89A0106FB52BB0C14A10A9EE26F92008C85A9", - "ldt_key": "C905DE5A4D9A71D42DEBC09CA3551456B86692AB157637FFA69626D880791891C34F54EDBB914AD5799E4B919C43C205AAE659D391A6A48A01D16362F35E653A", - "hmac_key": "6F2BE000125B82A2E33DC8C9E43705D60526645724BB0AD44B21DA54B3583BD5", - "adv_salt": "E304", - "plaintext": "71CCB1045AE70B3006C31956BBE79C0A8DAF6CF384AE2641DF5AA56D", - "ciphertext": "36CCD64BCF938CF027FB6AA76F22DF8E15313033B2B2ECA5D8C62CAC", - "metadata_key_hmac": "656F0A8E99EBACA3C4CDAFBFE368CF1F7B1D6D21298B353588FAE6102714D3C3" - }, - { - "key_seed": "F1F3A8615F2C5254F5705ED9C7B8DCC3E54EC6E26F976022A41FAEB58833CCE0", - "ldt_key": "B2F43E1E0EF3AC754BC7DBFB06150A03DECB6C13B2D59D372D32D1C4C95E12B17D05E104519226C34ED024AA42F35F97DF19228C7A960B3366FC81DED6D6067E", - "hmac_key": "46721F7126357AA3E1E1CF333D87CBE25D53A929EDE142A0B171661437FC65DC", - "adv_salt": "7375", - "plaintext": "5B457B5E1B1EB0C033A1EEA469BE0DA1", - "ciphertext": "0ED8CCF5D13E17B19C27E7E3E74547BE", - "metadata_key_hmac": "1A113F03BB294B74328BB167D3F86698BCEB4795D42F6CEF08463A36E0343E5A" - }, - { - "key_seed": "352DE4E9A05C50430F06E1F5E7E305DC268154FD8B4474C82E11CCF326480B2D", - "ldt_key": "FC1A43A901581AD08C41BDFD5717ACA525CD62F284AB836FB162B7F201C4B88153DF23BD6E6BE90A1551B3F7C0BC4F21F764F4846C403972F6E87D5F50E776F2", - "hmac_key": "11F04E1C99267F9104136A72CC88F46BE4413596C562F9C26BEA27146C19FAF5", - "adv_salt": "7F58", - "plaintext": "64790AADB293C27C49D18289226FED7768411D0A22", - "ciphertext": "457C6407FC9CF2E7C1DF8FC907743A6002AF353453", - "metadata_key_hmac": "0CB22738098D7215F402CD5AA6E005FE47F72505591F93AB693EDF5FF9BAF2AF" - }, - { - "key_seed": "66B6FAE0F6B0484EB7413DB51F7FCBAD1187BEFDDA329177ECD4B418A7CC557A", - "ldt_key": "3560736E3B71452A8935EF44775D1EA955B8C63268AD3A3DB58E4DFFCB9B3FD3BADFD7B71417BA845EA5EB88B2F5DBFB983CCD3AD3F39351C86294842660F489", - "hmac_key": "9095B581BE4680389A9281FD1FF244DB28BCA1F872EA4E00BBAE467D16B5683F", - "adv_salt": "E87E", - "plaintext": "C9374B60A3ED97BF64ACD5BF4CA75EBCCF", - "ciphertext": "9A0132A481D66099A9B5BF783BFE6E4616", - "metadata_key_hmac": "4A3ABD5626A0D2263CBA0259057FBD537B04B135D5674179516898AFEAF8781B" - }, - { - "key_seed": "46F24B770B1ADE0340A91C81D3693BB5AB1900050912279F737AF059CE02C9F9", - "ldt_key": "36C3BDC7A4BB377CEBB55F60E9E7B49CAEE166968492384F1596EDEA86EE2EC9BA2EA6B52C5C7564028C9057CE6E0938DFE4935E0AD02D44FC98050675B7DD06", - "hmac_key": "D01263CED254613D29A70B1A64F0989C574F08125F27BBA1BB1AE2EE68634348", - "adv_salt": "FEBE", - "plaintext": "0C9E2CCD8F9790D33FEFD640621545F6", - "ciphertext": "812EE0C2A14C097DFEEAABD5EF6C387F", - "metadata_key_hmac": "7C7747CE38CFE5AE657EF6AAA504C47B5447E641B19248C4F3B67180E9D3FAB8" - }, - { - "key_seed": "E71EDBE4DA0EA9CA5B4F083E56DE60643B96742B61C5948FA11ABE5FEE024324", - "ldt_key": "3F2DA23A6EFE5492830C82437E27FD26ED83BC22F573A4FA0B69129DB2E4DDDA60FD436DA8BC74F4380B740449AC54AD0E4CB963FB36C247216F3D2620ECAC2B", - "hmac_key": "65C79B5C0BAC21D938D560875098ED1CF44D198D765480A0FD9712FFA69536A7", - "adv_salt": "39DA", - "plaintext": "A6B6F2B67D86207B75568350E024ECAA971EA337A452C64CB411", - "ciphertext": "70A0F0C5798AA40E33E6E13570680070E185A862729EE27B45EB", - "metadata_key_hmac": "403423570D444DF6F0E23D5278F6E32598AF944DEB45119D10373C602E7EF470" - }, - { - "key_seed": "4E72EE3AD7EEA1800CC1FD0FFA52FFBC956AD61B610E6D52D172151550CA3EDF", - "ldt_key": "017F11C19586862084AC204AE3F2A4E6CBD0AF118C500691B035DE40E34655750E60261AB3659F38F4F2839B1707D1A1E18B4E4BA34995030889DF3E42A16CAA", - "hmac_key": "DDAC2A8278227BD24601C4E7A60E5EB5202C6E08B3DB91163BFD8398C2F115E0", - "adv_salt": "11A0", - "plaintext": "E05B79A5E3400C9620245A24519EB7C644E1F75D3A7E661EBED2A7E05B", - "ciphertext": "316D773ADD8E7760838511133B0494F1E53E5C376206924BA988CEFA6F", - "metadata_key_hmac": "1D9EB4F8E2B8C0FF61A768F9D4DE38C50441ABEFA389C5C896B800B0010E54CB" - }, - { - "key_seed": "29C4C4ACA1FE347FC57373BAE7B1608285BD124BD5D2ED1BCBE096CE34559BFE", - "ldt_key": "79BED0C41422EC9FC7FCDFD1A82F05FCCF4E2452720B22214D72C6B9832060C7C34FA7AF4203A5E71973EE0DC5FE4B6DEA39B2ECC4E6382CC227420B7A08C3A4", - "hmac_key": "74F0F33354E99AB617EF92E19126E6A23C5B7986274EE42EAE047879AABAF6CC", - "adv_salt": "CC68", - "plaintext": "19C23720321DCBFDA34B7CAEC42044C17C10", - "ciphertext": "C8B673F748D75F10860FDD68B0CECEAF628E", - "metadata_key_hmac": "DD707F9310D9F4F50CA323123C005021D62B18CD44DC1D2D7010F40E91BCDF6E" - }, - { - "key_seed": "8AC90D32CFFFF80DD40A0E9DCB9126CC68074D963E2C6D9B9094B897867B891F", - "ldt_key": "712BE11E8FFC957C1AFB7889E7F26836CE216F17BC5833DB37FD18E6C184F48EA4561A44036E3527E5845283C00A88F29DBEEB7C92D11AC8049A83400C60A7C8", - "hmac_key": "61B07AD48CCAC2A71B1684EFE7E3D1CA142CF20CA8D390356AF795107D3F215B", - "adv_salt": "DE3A", - "plaintext": "F686116AE03B1982F591A80C702F5E37CD9767FDDA1A3D18629A28F5102E49", - "ciphertext": "7B9046041C3D232BF1A0513FF1CDA1AC4AA4205664C3F6DB560EB8BE668A60", - "metadata_key_hmac": "5A0EA84490DAEC977401C1DF0BDCE4D7F69A15A082943190DF6D30B456BECD67" - }, - { - "key_seed": "A8CF63E3795D263AC7ECA88C9646EB1C20A0FB00C1A5DA5973C3D30687823311", - "ldt_key": "731278582AF984AF187232BC44EEB9C297A2DC0D54FB3948B2DF3ADF7D295AA1731BC316A1C95448800E2EF3604BA30CB616021ADA5AF671F7BCECE8D11B7FEB", - "hmac_key": "EFB2FC72054D63B14CB2966B174F328391B41D1B823F7A45598258857121BF81", - "adv_salt": "A42A", - "plaintext": "926736CFD879B5E15B5274341FC48863CF803CF0CB78CA2DFE", - "ciphertext": "EFA206EDC33DC9B6F294DF7FB0589297F3C70020326216759F", - "metadata_key_hmac": "88C796D31D909B1A958199EFE224524CD20ED2EF7F1219FCA961BAD79042A429" - }, - { - "key_seed": "6CC2DB3AA70FF4258F8DA394570A07C6D7C62DD97200F9272EF3C504DDF663F6", - "ldt_key": "C067AE2090E91FD5FFD9BDD87316638266123C1DC15955E42C1485A93B857660236CE6C91F6EF4E781BABE5FD227A3269A8EAA77F97B41761C4F2484554FC302", - "hmac_key": "B83AB0B2AD00256C8983CE49D6A76B6D3028D64889E8EBA67DCB9C08F8AEDBD7", - "adv_salt": "BC3B", - "plaintext": "D54AB6B6A4BD0152C6AB414F8FEE8C44D44237BC5A1F", - "ciphertext": "3DD97FD1611D5B3D0579D9766E4C5D607709BCD0CDED", - "metadata_key_hmac": "F5C8FA8870CAE6C2C48C59478942DADF5E08A7CD1FB872613A78DCC69085D8C5" - }, - { - "key_seed": "F3C4F33CDCE131D5DD270546F46E986717912EE27D246537CF7776C4238A04C1", - "ldt_key": "350EA4B98C555B9AE90900F547552580FAD3DB4C297FF3295602413FA7D6F6D905B735291C7EB4FFF834DB9601F479E2074F367BFC5D9F2F87B24489CBA05030", - "hmac_key": "1F0D7683CAFFF276AF4E63FD89028D69EE034F40CC5ADA7739ACFFDB712E24DD", - "adv_salt": "BCF1", - "plaintext": "DA459AC904B3634D1CDE2CF87ECDE60157ADDCC7F2F6C5", - "ciphertext": "45A3A3EC391FDFE6F56A592E0B428D9A200DCBA3866868", - "metadata_key_hmac": "FC1CE147E7A2C6CD10D9E52D4803C7C01F8874ECB52CB1E817E9C2EEEE9AAD3E" + "adv_salt": "BC3C", + "ciphertext": "E7BA016C044E5F65A32B7858C27BE1DB4B97640D5AC8F81CA166AA2A4AA955", + "hmac_key": "75A59414DD7AEAAE0518BCBD74A24850094E980E79EC63BC9B52349AB8210D66", + "identity_token_hmac": "FFC4D1BFDC4FBC90E39B089B90246AA5D32AB0D6407E0D1A2B327FC01AD2DFDE", + "key_seed": "03CCD2A359286FB1D0EDE3D61A340A2EDF0A7A9CC46F0F65CC2249021D650C50", + "ldt_key": "E1D3E029AE94ACB98A5B0FA63AD3FE4D52118E7D0615540C34B3427F3BDE06390BC26CC5303DB52260CD46696E9A245AC48B4299D72AC6DF95056A53A4004A01", + "plaintext": "63CD8D1E2EB4A2919FA24DB11E57C3F649D39FA14952A3FB0874A73B0B0CCD" } ]
diff --git a/nearby/presence/ldt_np_adv/src/lib.rs b/nearby/presence/ldt_np_adv/src/lib.rs index 542d6a5..1d202f7 100644 --- a/nearby/presence/ldt_np_adv/src/lib.rs +++ b/nearby/presence/ldt_np_adv/src/lib.rs
@@ -25,58 +25,104 @@ use array_view::ArrayView; use core::fmt; -use crypto_provider::{aes::BLOCK_SIZE, CryptoProvider}; -use ldt::{LdtDecryptCipher, LdtEncryptCipher, LdtError, Mix, Padder, Swap, XorPadder}; -use ldt_tbc::TweakableBlockCipher; -use np_hkdf::{legacy_ldt_expanded_salt, NpHmacSha256Key, NpKeySeedHkdf}; +use core::ops; +use crypto_provider::{aes::BLOCK_SIZE, CryptoProvider, CryptoRng, FromCryptoRng}; +use ldt::{LdtCipher, LdtDecryptCipher, LdtEncryptCipher, LdtError, Swap, XorPadder}; +use np_hkdf::{v0_ldt_expanded_salt, NpHmacSha256Key, NpKeySeedHkdf}; use xts_aes::XtsAes128; /// Max LDT-XTS-AES data size: `(2 * AES block size) - 1` pub const LDT_XTS_AES_MAX_LEN: usize = 31; -/// Legacy (v0) format uses a 14-byte metadata key -pub const NP_LEGACY_METADATA_KEY_LEN: usize = 14; +/// V0 format uses a 14-byte identity token +pub const V0_IDENTITY_TOKEN_LEN: usize = 14; -/// The salt included in an NP advertisement. +/// Max payload size once identity token prefix has been removed +pub const NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN: usize = LDT_XTS_AES_MAX_LEN - V0_IDENTITY_TOKEN_LEN; + +/// Length of a V0 advertisement salt +pub const V0_SALT_LEN: usize = 2; + +/// The salt included in a V0 NP advertisement. /// LDT does not use an IV but can instead incorporate the 2 byte, regularly rotated, /// salt from the advertisement payload and XOR it with the padded tweak data. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct LegacySalt { +pub struct V0Salt { /// Salt bytes extracted from the incoming NP advertisement - bytes: [u8; 2], + bytes: [u8; V0_SALT_LEN], } -impl LegacySalt { +impl V0Salt { /// Returns the salt as a byte array. - pub fn bytes(&self) -> &[u8; 2] { - &self.bytes + pub fn bytes(&self) -> [u8; V0_SALT_LEN] { + self.bytes } } -impl From<[u8; 2]> for LegacySalt { - fn from(arr: [u8; 2]) -> Self { +impl From<[u8; V0_SALT_LEN]> for V0Salt { + fn from(arr: [u8; V0_SALT_LEN]) -> Self { Self { bytes: arr } } } -/// [LdtEncryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function. -pub type LdtEncrypterXtsAes128<C> = LdtEncryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>; +/// "Short" 14-byte identity token type employed for V0 +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct V0IdentityToken([u8; V0_IDENTITY_TOKEN_LEN]); -/// A Nearby Presence specific LDT decrypter which verifies the hmac tag of the given payload -/// parameterized for XTS-AES-128 with the [Swap] mix function. -pub type LdtNpAdvDecrypterXtsAes128<C> = - LdtNpAdvDecrypter<{ BLOCK_SIZE }, LDT_XTS_AES_MAX_LEN, XtsAes128<C>, Swap, C>; +impl V0IdentityToken { + /// Constructs a V0 identity token from raw bytes. + pub const fn new(value: [u8; V0_IDENTITY_TOKEN_LEN]) -> Self { + Self(value) + } + /// Returns the underlying bytes + pub fn bytes(&self) -> [u8; V0_IDENTITY_TOKEN_LEN] { + self.0 + } + + /// Returns the token bytes as a slice + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl From<[u8; V0_IDENTITY_TOKEN_LEN]> for V0IdentityToken { + fn from(value: [u8; V0_IDENTITY_TOKEN_LEN]) -> Self { + Self(value) + } +} + +impl AsRef<[u8]> for V0IdentityToken { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl FromCryptoRng for V0IdentityToken { + fn new_random<R: CryptoRng>(rng: &mut R) -> Self { + Self(rng.gen()) + } +} + +/// [LdtEncryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function. +pub type NpLdtEncryptCipher<C> = LdtEncryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>; + +/// [LdtDecryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function. +type NpLdtDecryptCipher<C> = LdtDecryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>; + +/// Range of valid NP LDT message lengths for encryption/decryption, in a convenient form that +/// doesn't need a CryptoProvider parameter. +pub const VALID_INPUT_LEN: ops::Range<usize> = BLOCK_SIZE..BLOCK_SIZE * 2; /// Build a Nearby Presence specific LDT XTS-AES-128 decrypter from a provided [NpKeySeedHkdf] and /// metadata_key_hmac, with the [Swap] mix function pub fn build_np_adv_decrypter_from_key_seed<C: CryptoProvider>( key_seed: &NpKeySeedHkdf<C>, - metadata_key_tag: [u8; 32], -) -> LdtNpAdvDecrypterXtsAes128<C> { + identity_token_hmac: [u8; 32], +) -> AuthenticatedNpLdtDecryptCipher<C> { build_np_adv_decrypter( - &key_seed.legacy_ldt_key(), - metadata_key_tag, - key_seed.legacy_metadata_key_hmac_key(), + &key_seed.v0_ldt_key(), + identity_token_hmac, + key_seed.v0_identity_token_hmac_key(), ) } @@ -84,28 +130,25 @@ /// with the [Swap] mix function pub fn build_np_adv_decrypter<C: CryptoProvider>( ldt_key: &ldt::LdtKey<xts_aes::XtsAes128Key>, - metadata_key_tag: [u8; 32], - metadata_key_hmac_key: NpHmacSha256Key<C>, -) -> LdtNpAdvDecrypterXtsAes128<C> { - LdtNpAdvDecrypter { - ldt_decrypter: LdtXtsAes128Decrypter::<C>::new(ldt_key), - metadata_key_tag, - metadata_key_hmac_key, + identity_token_hmac: [u8; 32], + identity_token_hmac_key: NpHmacSha256Key, +) -> AuthenticatedNpLdtDecryptCipher<C> { + AuthenticatedNpLdtDecryptCipher { + ldt_decrypter: NpLdtDecryptCipher::<C>::new(ldt_key), + metadata_key_tag: identity_token_hmac, + metadata_key_hmac_key: identity_token_hmac_key, } } -// [LdtDecryptCipher] parameterized for XTS-AES-128 with the [Swap] mix function. -type LdtXtsAes128Decrypter<C> = LdtDecryptCipher<{ BLOCK_SIZE }, XtsAes128<C>, Swap>; - /// Decrypts and validates a NP legacy format advertisement encrypted with LDT. /// /// A NP legacy advertisement will always be in the format of: /// -/// Header (1 byte) | Identity DE header (1 byte) | Salt (2 bytes) | Identity (14 bytes) | repeated +/// Header (1 byte) | Salt (2 bytes) | Identity token (14 bytes) | repeated /// { DE header | DE payload } /// /// Example: -/// Header (1 byte) | Identity DE header (1 byte) | Salt (2 bytes) | Identity (14 bytes) | +/// Header (1 byte) | Salt (2 bytes) | Identity token (14 bytes) | /// Tx power DE header (1 byte) | Tx power (1 byte) | Action DE header(1 byte) | action (1-3 bytes) /// /// The ciphertext bytes will always start with the Identity through the end of the @@ -117,70 +160,61 @@ /// `O` is the max output size (must be 2 * B - 1). /// `T` is the tweakable block cipher used by LDT. /// `M` is the mix function used by LDT. -pub struct LdtNpAdvDecrypter< - const B: usize, - const O: usize, - T: TweakableBlockCipher<B>, - M: Mix, - C: CryptoProvider, -> { - ldt_decrypter: LdtDecryptCipher<B, T, M>, +pub struct AuthenticatedNpLdtDecryptCipher<C: CryptoProvider> { + ldt_decrypter: LdtDecryptCipher<BLOCK_SIZE, XtsAes128<C>, Swap>, metadata_key_tag: [u8; 32], - metadata_key_hmac_key: NpHmacSha256Key<C>, + metadata_key_hmac_key: NpHmacSha256Key, } -impl<const B: usize, const O: usize, T, M, C> LdtNpAdvDecrypter<B, O, T, M, C> -where - T: TweakableBlockCipher<B>, - M: Mix, - C: CryptoProvider, -{ +impl<C: CryptoProvider> AuthenticatedNpLdtDecryptCipher<C> { /// Decrypt an advertisement payload using the provided padder. /// - /// If the plaintext's metadata key matches this item's MAC, return the plaintext, otherwise `None`. + /// If the plaintext's identity token matches this decrypter's MAC, returns the verified identity + /// token and the remaining plaintext (the bytes after the identity token). /// /// NOTE: because LDT acts as a PRP over the entire message, tampering with any bit scrambles /// the whole message, so we can leverage the MAC on just the metadata key to ensure integrity /// for the whole message. /// /// # Errors - /// - If `payload` has a length outside of `[B, B * 2)`. + /// - If `payload` has a length outside `[BLOCK_SIZE, BLOCK_SIZE * 2)`. /// - If the decrypted plaintext fails its HMAC validation - pub fn decrypt_and_verify<P: Padder<B, T>>( + #[allow(clippy::expect_used, clippy::indexing_slicing)] + pub fn decrypt_and_verify( &self, payload: &[u8], - padder: &P, - ) -> Result<ArrayView<u8, O>, LdtAdvDecryptError> { - assert_eq!(B * 2 - 1, O); // should be compiled away - - // have to check length before passing to LDT to ensure copying into the buffer is safe - if payload.len() < B || payload.len() > O { - return Err(LdtAdvDecryptError::InvalidLength(payload.len())); - } - + padder: &XorPadder<BLOCK_SIZE>, + ) -> Result< + (V0IdentityToken, ArrayView<u8, NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN>), + LdtAdvDecryptError, + > { // we copy to avoid exposing plaintext that hasn't been validated w/ hmac - let mut buffer = [0_u8; O]; - buffer[..payload.len()].copy_from_slice(payload); + let mut buffer = [0_u8; LDT_XTS_AES_MAX_LEN]; + let populated_buffer = buffer + .get_mut(..payload.len()) + .ok_or(LdtAdvDecryptError::InvalidLength(payload.len()))?; + populated_buffer.copy_from_slice(payload); - #[allow(clippy::expect_used)] - self.ldt_decrypter - .decrypt(&mut buffer[..payload.len()], padder) - .map_err(|e| match e { - LdtError::InvalidLength(l) => LdtAdvDecryptError::InvalidLength(l), - }) - .and_then(|_| { - self.metadata_key_hmac_key - .verify_hmac(&buffer[..NP_LEGACY_METADATA_KEY_LEN], self.metadata_key_tag) - .map_err(|_| LdtAdvDecryptError::MacMismatch) - .map(|_| { - ArrayView::try_from_array(buffer, payload.len()) - .expect("this will never be hit because the length is validated above") - }) - }) + self.ldt_decrypter.decrypt(populated_buffer, padder).map_err(|e| match e { + LdtError::InvalidLength(l) => LdtAdvDecryptError::InvalidLength(l), + })?; + // slice is safe since input is a valid LDT-XTS-AES len + let identity_token = &populated_buffer[..V0_IDENTITY_TOKEN_LEN]; + self.metadata_key_hmac_key + .verify_hmac::<C>(identity_token, self.metadata_key_tag) + .map_err(|_| LdtAdvDecryptError::MacMismatch)?; + + let token_arr: [u8; V0_IDENTITY_TOKEN_LEN] = + identity_token.try_into().expect("Length verified above"); + Ok(( + token_arr.into(), + ArrayView::try_from_slice(&buffer[V0_IDENTITY_TOKEN_LEN..payload.len()]) + .expect("Buffer len less token len is the max output len"), + )) } } -/// Errors that can occur during [LdtNpAdvDecrypter::decrypt_and_verify]. +/// Errors that can occur during [AuthenticatedNpLdtDecryptCipher::decrypt_and_verify]. #[derive(Debug, PartialEq, Eq)] pub enum LdtAdvDecryptError { /// The ciphertext data was an invalid length. @@ -199,9 +233,8 @@ } } } + /// Build a XorPadder by HKDFing the NP advertisement salt -pub fn salt_padder<const B: usize, C: CryptoProvider>(salt: LegacySalt) -> XorPadder<{ B }> { - // Assuming that the tweak size == the block size here, which it is for XTS. - // If that's ever not true, yet another generic parameter will address that. - XorPadder::from(legacy_ldt_expanded_salt::<B, C>(&salt.bytes)) +pub fn salt_padder<C: CryptoProvider>(salt: V0Salt) -> XorPadder<BLOCK_SIZE> { + XorPadder::from(v0_ldt_expanded_salt::<C>(&salt.bytes)) }
diff --git a/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs b/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs index cf176dd..488858d 100644 --- a/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs +++ b/nearby/presence/ldt_np_adv/src/np_adv_test_vectors.rs
@@ -11,21 +11,23 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + #![allow(clippy::indexing_slicing, clippy::unwrap_used, clippy::panic, clippy::expect_used)] extern crate std; + use crate::{ - build_np_adv_decrypter_from_key_seed, salt_padder, LdtEncrypterXtsAes128, LegacySalt, - NP_LEGACY_METADATA_KEY_LEN, + build_np_adv_decrypter_from_key_seed, salt_padder, NpLdtEncryptCipher, V0Salt, + V0_IDENTITY_TOKEN_LEN, }; use anyhow::anyhow; use crypto_provider_default::CryptoProviderImpl; -use rand::Rng; -use rand_ext::{random_vec_rc, seeded_rng}; +use ldt::LdtCipher; use serde_json::json; use std::vec::Vec; use std::{fs, io::Read as _, println, string::String}; use test_helper::{extract_key_array, extract_key_vec}; +use test_vector_hkdf::TestVectorHkdf; #[test] fn np_adv_test_vectors() -> Result<(), anyhow::Error> { @@ -39,26 +41,26 @@ _ => return Err(anyhow!("bad json")), }; - assert_eq!(1000, test_cases.len()); + assert_eq!(100, test_cases.len()); for tc in test_cases { let key_seed = extract_key_array::<32>(&tc, "key_seed"); let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let ldt_key = hkdf.legacy_ldt_key(); - let hmac_key = hkdf.legacy_metadata_key_hmac_key(); + let ldt_key = hkdf.v0_ldt_key(); + let hmac_key = hkdf.v0_identity_token_hmac_key(); assert_eq!(&extract_key_vec(&tc, "ldt_key"), &ldt_key.as_concatenated()); assert_eq!(&extract_key_vec(&tc, "hmac_key"), &hmac_key.as_bytes()); - let salt = LegacySalt::from(extract_key_array(&tc, "adv_salt")); - let padder = salt_padder::<16, CryptoProviderImpl>(salt); + let salt = V0Salt::from(extract_key_array(&tc, "adv_salt")); + let padder = salt_padder::<CryptoProviderImpl>(salt); - let ldt_enc = LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&ldt_key); + let ldt_enc = NpLdtEncryptCipher::<CryptoProviderImpl>::new(&ldt_key); let decrypter = build_np_adv_decrypter_from_key_seed( &hkdf, - extract_key_array(&tc, "metadata_key_hmac"), + extract_key_array(&tc, "identity_token_hmac"), ); let plaintext = extract_key_vec(&tc, "plaintext"); @@ -69,9 +71,11 @@ assert_eq!(ciphertext, ciphertext_actual); - let plaintext_actual = decrypter.decrypt_and_verify(&ciphertext, &padder).unwrap(); + let (identity_token, plaintext_actual) = + decrypter.decrypt_and_verify(&ciphertext, &padder).unwrap(); - assert_eq!(&plaintext, plaintext_actual.as_slice()); + assert_eq!(&plaintext[..V0_IDENTITY_TOKEN_LEN], identity_token.as_slice()); + assert_eq!(&plaintext[V0_IDENTITY_TOKEN_LEN..], plaintext_actual.as_slice()); } Ok(()) @@ -81,23 +85,34 @@ #[ignore] #[test] fn gen_test_vectors() { - let mut rng = seeded_rng(); - let mut array = Vec::<serde_json::Value>::new(); - for _ in 0..1_000 { - let len = - rng.gen_range(crypto_provider::aes::BLOCK_SIZE..crypto_provider::aes::BLOCK_SIZE * 2); - let plaintext = random_vec_rc(&mut rng, len); - let key_seed: [u8; 32] = rng.gen(); + for i in 0_u32..100 { + let test_vector_seed_hkdf = TestVectorHkdf::<CryptoProviderImpl>::new( + "NP LDT test vectors Y7yJTRXy+8saKiYSu76/TbabkAFhK55zF8QutxcQlGc", + &i.to_be_bytes(), + ); + + let len = test_vector_seed_hkdf + .derive_range_element( + "plaintext len", + crypto_provider::aes::BLOCK_SIZE as u64 + ..=crypto_provider::aes::BLOCK_SIZE as u64 * 2 - 1, + ) + .try_into() + .unwrap(); + let plaintext = test_vector_seed_hkdf.derive_vec("plaintext", len); + let key_seed: [u8; 32] = test_vector_seed_hkdf.derive_array("key seed"); let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let ldt_key = hkdf.legacy_ldt_key(); - let hmac_key = hkdf.legacy_metadata_key_hmac_key(); - let hmac: [u8; 32] = hmac_key.calculate_hmac(&plaintext[..NP_LEGACY_METADATA_KEY_LEN]); - let ldt_enc = LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&ldt_key); + let ldt_key = hkdf.v0_ldt_key(); + let hmac_key = hkdf.v0_identity_token_hmac_key(); + let hmac: [u8; 32] = + hmac_key.calculate_hmac::<CryptoProviderImpl>(&plaintext[..V0_IDENTITY_TOKEN_LEN]); + let ldt_enc = NpLdtEncryptCipher::<CryptoProviderImpl>::new(&ldt_key); - let padder = salt_padder::<16, CryptoProviderImpl>(LegacySalt::from(rng.gen::<[u8; 2]>())); + let salt = V0Salt::from(test_vector_seed_hkdf.derive_array("salt")); + let padder = salt_padder::<CryptoProviderImpl>(salt); let mut ciphertext = plaintext.clone(); ldt_enc.encrypt(&mut ciphertext[..], &padder).unwrap(); @@ -105,12 +120,13 @@ "key_seed": hex::encode_upper(key_seed), "ldt_key": hex::encode_upper(ldt_key.as_concatenated()), "hmac_key": hex::encode_upper(hmac_key.as_bytes()), - "adv_salt": hex::encode_upper(rng.gen::<[u8; 2]>()), + "adv_salt": hex::encode_upper(salt.bytes()), "plaintext": hex::encode_upper(plaintext), "ciphertext": hex::encode_upper(ciphertext), - "metadata_key_hmac": hex::encode_upper(hmac), + "identity_token_hmac": hex::encode_upper(hmac), })); } println!("{}", serde_json::ser::to_string_pretty(&array).unwrap()); + panic!("Don't leave this test enabled. Meanwhile, enjoy the text output above."); }
diff --git a/nearby/presence/ldt_np_adv/src/tests.rs b/nearby/presence/ldt_np_adv/src/tests.rs index 30bc7b6..a731762 100644 --- a/nearby/presence/ldt_np_adv/src/tests.rs +++ b/nearby/presence/ldt_np_adv/src/tests.rs
@@ -16,18 +16,23 @@ extern crate alloc; use crate::{ - build_np_adv_decrypter_from_key_seed, salt_padder, LdtAdvDecryptError, LdtEncrypterXtsAes128, - LdtNpAdvDecrypterXtsAes128, LdtXtsAes128Decrypter, LegacySalt, LDT_XTS_AES_MAX_LEN, - NP_LEGACY_METADATA_KEY_LEN, + build_np_adv_decrypter_from_key_seed, salt_padder, AuthenticatedNpLdtDecryptCipher, + LdtAdvDecryptError, NpLdtDecryptCipher, NpLdtEncryptCipher, V0IdentityToken, V0Salt, + LDT_XTS_AES_MAX_LEN, V0_IDENTITY_TOKEN_LEN, }; use alloc::vec::Vec; use crypto_provider::{CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; -use ldt::{DefaultPadder, LdtError, LdtKey, XorPadder}; +use ldt::{DefaultPadder, LdtCipher, LdtError, LdtKey, XorPadder}; use np_hkdf::NpKeySeedHkdf; use rand::Rng; use rand_ext::{random_bytes, random_vec, seeded_rng}; +extern crate std; + +use crypto_provider::aes::BLOCK_SIZE; +use std::vec; + #[test] fn decrypt_matches_correct_ciphertext() { let mut rng = CryptoRng::new(); @@ -35,10 +40,11 @@ let test_state = make_test_components::<CryptoProviderImpl>(&mut rng); let cipher = build_np_adv_decrypter_from_key_seed(&test_state.hkdf, test_state.hmac); - let decrypted = + let (token, plaintext) = cipher.decrypt_and_verify(&test_state.ciphertext, &test_state.padder).unwrap(); - assert_eq!(&test_state.plaintext, decrypted.as_ref()); + assert_eq!(test_state.identity_token, token); + assert_eq!(&test_state.remaining_plaintext, plaintext.as_ref()); } } @@ -85,7 +91,7 @@ let cipher = test_state.ldt_enc; - let mut plaintext_copy = test_state.plaintext.clone(); + let mut plaintext_copy = test_state.all_plaintext.clone(); cipher.encrypt(&mut plaintext_copy[..], &test_state.padder).unwrap(); assert_eq!(test_state.ciphertext, plaintext_copy); @@ -96,83 +102,146 @@ #[allow(deprecated)] fn encrypt_too_short_err() { let ldt_enc = - LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64])); + NpLdtEncryptCipher::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64])); - let mut payload = [0; 7]; - assert_eq!(Err(LdtError::InvalidLength(7)), ldt_enc.encrypt(&mut payload, &DefaultPadder)); + let mut payload = vec![0; BLOCK_SIZE - 1]; + assert_eq!( + Err(LdtError::InvalidLength(BLOCK_SIZE - 1)), + ldt_enc.encrypt(&mut payload, &DefaultPadder) + ); } #[test] #[allow(deprecated)] fn encrypt_too_long_err() { let ldt_enc = - LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64])); + NpLdtEncryptCipher::<CryptoProviderImpl>::new(&LdtKey::from_concatenated(&[0; 64])); - let mut payload = [0; 40]; - assert_eq!(Err(LdtError::InvalidLength(40)), ldt_enc.encrypt(&mut payload, &DefaultPadder)); + let mut payload = vec![0; BLOCK_SIZE * 2]; + assert_eq!( + Err(LdtError::InvalidLength(BLOCK_SIZE * 2)), + ldt_enc.encrypt(&mut payload, &DefaultPadder) + ); } #[test] fn decrypt_too_short_err() { - let adv_cipher = LdtNpAdvDecrypterXtsAes128 { - ldt_decrypter: LdtXtsAes128Decrypter::<CryptoProviderImpl>::new( - &LdtKey::from_concatenated(&[0; 64]), - ), - metadata_key_tag: [0; 32], - metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<CryptoProviderImpl>::from([0; 32]), - }; + let adv_cipher: AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl> = + AuthenticatedNpLdtDecryptCipher { + ldt_decrypter: NpLdtDecryptCipher::<CryptoProviderImpl>::new( + &LdtKey::from_concatenated(&[0; 64]), + ), + metadata_key_tag: [0; 32], + metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::from([0; 32]), + }; - let payload = [0; 7]; + // 1 byte less than a full block + let payload = vec![0; BLOCK_SIZE - 1]; assert_eq!( - Err(LdtAdvDecryptError::InvalidLength(7)), - adv_cipher.decrypt_and_verify(&payload, &DefaultPadder) + Err(LdtAdvDecryptError::InvalidLength(BLOCK_SIZE - 1)), + adv_cipher.decrypt_and_verify(&payload, &XorPadder::from([0_u8; BLOCK_SIZE])) ); } #[test] fn decrypt_too_long_err() { - let adv_cipher = LdtNpAdvDecrypterXtsAes128 { - ldt_decrypter: LdtXtsAes128Decrypter::<CryptoProviderImpl>::new( - &LdtKey::from_concatenated(&[0; 64]), - ), - metadata_key_tag: [0; 32], - metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::<CryptoProviderImpl>::from([0; 32]), - }; + let adv_cipher: AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl> = + AuthenticatedNpLdtDecryptCipher { + ldt_decrypter: NpLdtDecryptCipher::<CryptoProviderImpl>::new( + &LdtKey::from_concatenated(&[0; 64]), + ), + metadata_key_tag: [0; 32], + metadata_key_hmac_key: np_hkdf::NpHmacSha256Key::from([0; 32]), + }; - let payload = [0; 40]; + // 2 full blocks + let payload = [0; BLOCK_SIZE * 2]; assert_eq!( - Err(LdtAdvDecryptError::InvalidLength(40)), - adv_cipher.decrypt_and_verify(&payload, &DefaultPadder) + Err(LdtAdvDecryptError::InvalidLength(BLOCK_SIZE * 2)), + adv_cipher.decrypt_and_verify(&payload, &XorPadder::from([0; BLOCK_SIZE])) ); } +#[test] +fn verify_input_len_const() { + // make sure it matches the authoritative upstream + assert_eq!(crate::VALID_INPUT_LEN, NpLdtEncryptCipher::<CryptoProviderImpl>::VALID_INPUT_LEN); +} + +#[test] +fn ldt_ffi_test_scenario() { + // used in ldt_ffi_tests.cc and LdtNpJniTests + let key_seed: [u8; 32] = [ + 204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, 184, 148, 30, 209, 154, 29, 54, 14, + 117, 224, 152, 200, 193, 94, 107, 28, 194, 182, 32, 205, 57, + ]; + + let salt: V0Salt = [12, 15].into(); + let plaintext = [ + 205_u8, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174, 164, 0, 64, 200, 214, + 123, + ]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let ldt_key = hkdf.v0_ldt_key(); + let identity_token_hmac = hkdf + .v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&plaintext[..V0_IDENTITY_TOKEN_LEN]); + let decrypter = build_np_adv_decrypter_from_key_seed(&hkdf, identity_token_hmac); + + let padder = salt_padder::<CryptoProviderImpl>(salt); + let mut ciphertext = plaintext; + NpLdtEncryptCipher::<CryptoProviderImpl>::new(&ldt_key) + .encrypt(&mut ciphertext, &padder) + .unwrap(); + + let (token, contents) = decrypter.decrypt_and_verify(&ciphertext, &padder).unwrap(); + assert_eq!(&plaintext[..V0_IDENTITY_TOKEN_LEN], token.as_slice()); + assert_eq!(&plaintext[V0_IDENTITY_TOKEN_LEN..], contents.as_slice()); + + // Uncomment if updating the FFI test + // { + // use std::println; + // use test_helper::hex_bytes; + // println!("Key seed:\n{}\n{}", hex_bytes(&key_seed), hex::encode_upper(&key_seed)); + // println!("Identity token HMAC:\n{}\n{}", hex_bytes(&identity_token_hmac), hex::encode_upper(&identity_token_hmac)); + // println!("Plaintext:\n{}\n{}", hex_bytes(&plaintext), hex::encode_upper(&plaintext)); + // println!("Salt:\n{}\n{}", hex_bytes(salt.bytes()), hex::encode_upper(salt.bytes())); + // println!("Ciphertext:\n{}\n{}", hex_bytes(&ciphertext), hex::encode_upper(&ciphertext)); + // panic!(); + // } +} + /// Returns (plaintext, ciphertext, padder, hmac key, MAC, ldt) fn make_test_components<C: crypto_provider::CryptoProvider>( rng: &mut C::CryptoRng, ) -> LdtAdvTestComponents<C> { // [1, 2) blocks of XTS-AES let mut rc_rng = seeded_rng(); - let payload_len = rc_rng - .gen_range(crypto_provider::aes::BLOCK_SIZE..=(crypto_provider::aes::BLOCK_SIZE * 2 - 1)); - let plaintext = random_vec::<C>(rng, payload_len); + let payload_len = rc_rng.gen_range(BLOCK_SIZE..=(BLOCK_SIZE * 2 - 1)); + let all_plaintext = random_vec::<C>(rng, payload_len); - let salt = LegacySalt { bytes: random_bytes::<2, C>(rng) }; - let padder = salt_padder::<16, C>(salt); + let salt = V0Salt { bytes: random_bytes::<2, C>(rng) }; + let padder = salt_padder::<C>(salt); let key_seed: [u8; 32] = random_bytes::<32, C>(rng); let hkdf = np_hkdf::NpKeySeedHkdf::new(&key_seed); - let ldt_key = hkdf.legacy_ldt_key(); - let hmac_key = hkdf.legacy_metadata_key_hmac_key(); - let hmac: [u8; 32] = hmac_key.calculate_hmac(&plaintext[..NP_LEGACY_METADATA_KEY_LEN]); + let ldt_key = hkdf.v0_ldt_key(); + let hmac_key = hkdf.v0_identity_token_hmac_key(); + let identity_token: [u8; V0_IDENTITY_TOKEN_LEN] = + all_plaintext[..V0_IDENTITY_TOKEN_LEN].try_into().unwrap(); + let hmac: [u8; 32] = hmac_key.calculate_hmac::<C>(&identity_token); - let ldt_enc = LdtEncrypterXtsAes128::<C>::new(&ldt_key); + let ldt_enc = NpLdtEncryptCipher::<C>::new(&ldt_key); let mut ciphertext = [0_u8; LDT_XTS_AES_MAX_LEN]; - ciphertext[..plaintext.len()].copy_from_slice(&plaintext); - ldt_enc.encrypt(&mut ciphertext[..plaintext.len()], &padder).unwrap(); - + ciphertext[..all_plaintext.len()].copy_from_slice(&all_plaintext); + ldt_enc.encrypt(&mut ciphertext[..all_plaintext.len()], &padder).unwrap(); + let remaining_plaintext = all_plaintext[V0_IDENTITY_TOKEN_LEN..].to_vec(); LdtAdvTestComponents { - plaintext, + all_plaintext, + identity_token: identity_token.into(), + remaining_plaintext, ciphertext: ciphertext[..payload_len].to_vec(), padder, hmac, @@ -182,10 +251,38 @@ } struct LdtAdvTestComponents<C: CryptoProvider> { - plaintext: Vec<u8>, + all_plaintext: Vec<u8>, + identity_token: V0IdentityToken, + /// Plaintext after the identity token + remaining_plaintext: Vec<u8>, ciphertext: Vec<u8>, - padder: XorPadder<{ crypto_provider::aes::BLOCK_SIZE }>, + padder: XorPadder<{ BLOCK_SIZE }>, hmac: [u8; 32], - ldt_enc: LdtEncrypterXtsAes128<C>, + ldt_enc: NpLdtEncryptCipher<C>, hkdf: NpKeySeedHkdf<C>, } + +mod coverage_gaming { + extern crate std; + + use crate::{V0IdentityToken, V0_IDENTITY_TOKEN_LEN}; + use crypto_provider::{CryptoProvider, CryptoRng}; + use crypto_provider_default::CryptoProviderImpl; + use std::{collections, format}; + + #[test] + fn legacy_identity_token() { + let token = V0IdentityToken::from([0; V0_IDENTITY_TOKEN_LEN]); + // debug + let _ = format!("{:?}", token); + // hash + let _ = collections::HashSet::new().insert(&token); + // bytes + assert_eq!(token.0, token.bytes()); + // AsRef + assert_eq!(token.0.as_slice(), token.as_ref()); + // FromCryptoRng + let mut rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); + let _: V0IdentityToken = rng.gen(); + } +}
diff --git a/nearby/presence/ldt_np_adv_ffi/c/fuzz/ldt_fuzzer.cc b/nearby/presence/ldt_np_adv_ffi/c/fuzz/ldt_fuzzer.cc index dbe136d..8e4f28f 100644 --- a/nearby/presence/ldt_np_adv_ffi/c/fuzz/ldt_fuzzer.cc +++ b/nearby/presence/ldt_np_adv_ffi/c/fuzz/ldt_fuzzer.cc
@@ -82,11 +82,11 @@ // https://commondatastorage.googleapis.com/chromium-boringssl-docs/hkdf.h.html // 32 byte HMAC-SHA256 key uint8_t metadata_key_hmac_key[32] = {0}; - auto result = HKDF( - metadata_key_hmac_key, sizeof(metadata_key_hmac_key), EVP_sha256(), - (const uint8_t *)&key_seed.bytes, (size_t)32, - (const uint8_t *)"Google Nearby", (size_t)13, - (const uint8_t *)"Legacy metadata key verification HMAC key", (size_t)41); + auto result = HKDF(metadata_key_hmac_key, sizeof(metadata_key_hmac_key), + EVP_sha256(), (const uint8_t *)&key_seed.bytes, (size_t)32, + (const uint8_t *)"Google Nearby", (size_t)13, + (const uint8_t *)"V0 Identity token verification HMAC key", + (size_t)39); EXPECT_EQ(1, result); // calculate metadata key hmac using hkdf'd hmac key NpMetadataKeyHmac metadata_key_hmac = {.bytes = {0}};
diff --git a/nearby/presence/ldt_np_adv_ffi/c/tests/ldt_ffi_tests.cc b/nearby/presence/ldt_np_adv_ffi/c/tests/ldt_ffi_tests.cc index 7cd1fb3..65e0f68 100644 --- a/nearby/presence/ldt_np_adv_ffi/c/tests/ldt_ffi_tests.cc +++ b/nearby/presence/ldt_np_adv_ffi/c/tests/ldt_ffi_tests.cc
@@ -18,6 +18,7 @@ #include <algorithm> #include <fstream> +#include <iomanip> // TODO: get multi threaded tests working on windows #ifndef _WIN32 @@ -36,9 +37,9 @@ 204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, 184, 148, 30, 209, 154, 29, 54, 14, 117, 224, 152, 200, 193, 94, 107, 28, 194, 182, 32, 205, 57}; static const uint8_t KNOWN_HMAC_BYTES[] = { - 223, 185, 10, 31, 155, 31, 226, 141, 24, 187, 204, - 165, 34, 64, 181, 204, 44, 203, 95, 141, 82, 137, - 163, 203, 100, 235, 53, 65, 202, 97, 75, 180}; + 0xB4, 0xC5, 0x9F, 0xA5, 0x99, 0x24, 0x1B, 0x81, 0x75, 0x8D, 0x97, + 0x6B, 0x5A, 0x62, 0x1C, 0x05, 0x23, 0x2F, 0xE1, 0xBF, 0x89, 0xAE, + 0x59, 0x87, 0xCA, 0x25, 0x4C, 0x35, 0x54, 0xDC, 0xE5, 0x0E}; static const uint8_t TEST_DATA_BYTES[] = {205, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174, 164, 0, 64, 200, 214, 123}; @@ -65,7 +66,7 @@ static void hex_string_to_bytes(const char *hexString, uint8_t *out, size_t len) { for (size_t count = 0; count < len; count++) { - sscanf(hexString, "%2hhx", &out[count]); // NOLINT(cert-err34-c) + sscanf(hexString, "%2hhx", &out[count]); // NOLINT(cert-err34-c) hexString += 2; } } @@ -93,11 +94,11 @@ if (!parsingSuccessful) { std::cout << reader.getFormattedErrorMessages() << "\n"; } - ASSERT_TRUE(root.size() == 1000); + ASSERT_TRUE(root.size() == 100); for (const auto &v : root) { auto key_seed = v["key_seed"].asCString(); - auto metadata_key_hmac = v["metadata_key_hmac"].asCString(); + auto identity_token_hmac = v["identity_token_hmac"].asCString(); auto adv_salt = v["adv_salt"].asCString(); auto plaintext = v["plaintext"].asCString(); auto ciphertext = v["ciphertext"].asCString(); @@ -105,12 +106,12 @@ NpLdtKeySeed np_key_seed; auto len = strlen(key_seed) / 2; hex_string_to_bytes(key_seed, np_key_seed.bytes, len); - ASSERT_EQ(len, 32); + ASSERT_EQ(len, 32u); NpMetadataKeyHmac known_hmac; - len = strlen(metadata_key_hmac) / 2; - hex_string_to_bytes(metadata_key_hmac, known_hmac.bytes, len); - ASSERT_EQ(len, 32); + len = strlen(identity_token_hmac) / 2; + hex_string_to_bytes(identity_token_hmac, known_hmac.bytes, len); + ASSERT_EQ(len, 32u); NpLdtEncryptHandle enc_handle = NpLdtEncryptCreate(np_key_seed); ASSERT_TRUE(enc_handle.handle != 0); @@ -118,7 +119,7 @@ NpLdtSalt salt_data; len = strlen(adv_salt) / 2; hex_string_to_bytes(adv_salt, salt_data.bytes, len); - ASSERT_TRUE(len == 2); + ASSERT_TRUE(len == 2u); len = strlen(plaintext) / 2; auto buffer = (uint8_t *)malloc(len); @@ -294,7 +295,6 @@ pthread_cond_broadcast(&cond); // Wait for them all to finish and check the status - for (i = 0; i < num_threads; i++) - ASSERT_EQ(pthread_join(tid[i], nullptr), 0); + for (i = 0; i < num_threads; i++) ASSERT_EQ(pthread_join(tid[i], nullptr), 0); } #endif
diff --git a/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs b/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs index 9a19562..669f2bb 100644 --- a/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs +++ b/nearby/presence/ldt_np_adv_ffi/src/handle_map.rs
@@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::Box; use crate::LdtAdvDecrypter; use crate::LdtAdvEncrypter; use core::marker::PhantomData;
diff --git a/nearby/presence/ldt_np_adv_ffi/src/lib.rs b/nearby/presence/ldt_np_adv_ffi/src/lib.rs index 839135e..3ad6af4 100644 --- a/nearby/presence/ldt_np_adv_ffi/src/lib.rs +++ b/nearby/presence/ldt_np_adv_ffi/src/lib.rs
@@ -24,19 +24,19 @@ extern crate alloc; -use alloc::boxed::Box; use core::slice; use crypto_provider_default::CryptoProviderImpl; +use ldt::LdtCipher; use ldt_np_adv::{ - build_np_adv_decrypter_from_key_seed, salt_padder, LdtAdvDecryptError, LdtEncrypterXtsAes128, - LdtNpAdvDecrypterXtsAes128, LegacySalt, + build_np_adv_decrypter_from_key_seed, salt_padder, AuthenticatedNpLdtDecryptCipher, + LdtAdvDecryptError, NpLdtEncryptCipher, V0Salt, V0_IDENTITY_TOKEN_LEN, }; use np_hkdf::NpKeySeedHkdf; mod handle_map; -pub(crate) type LdtAdvDecrypter = LdtNpAdvDecrypterXtsAes128<CryptoProviderImpl>; -pub(crate) type LdtAdvEncrypter = LdtEncrypterXtsAes128<CryptoProviderImpl>; +pub(crate) type LdtAdvDecrypter = AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl>; +pub(crate) type LdtAdvEncrypter = NpLdtEncryptCipher<CryptoProviderImpl>; const SUCCESS: i32 = 0; @@ -81,7 +81,7 @@ #[no_mangle] extern "C" fn NpLdtEncryptCreate(key_seed: NpLdtKeySeed) -> NpLdtEncryptHandle { let cipher = LdtAdvEncrypter::new( - &NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed.bytes).legacy_ldt_key(), + &NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed.bytes).v0_ldt_key(), ); let handle = handle_map::get_enc_handle_map().insert::<CryptoProviderImpl>(Box::new(cipher)); NpLdtEncryptHandle { handle } @@ -116,7 +116,7 @@ ) -> i32 { map_to_error_code(|| { let data = unsafe { slice::from_raw_parts_mut(buffer, buffer_len) }; - let padder = salt_padder::<16, CryptoProviderImpl>(LegacySalt::from(salt.bytes)); + let padder = salt_padder::<CryptoProviderImpl>(V0Salt::from(salt.bytes)); handle_map::get_enc_handle_map() .get(&handle.handle) .map(|cipher| { @@ -137,8 +137,9 @@ ) -> i32 { map_to_error_code(|| { let data = unsafe { slice::from_raw_parts_mut(buffer, buffer_len) }; - let padder = salt_padder::<16, CryptoProviderImpl>(LegacySalt::from(salt.bytes)); + let padder = salt_padder::<CryptoProviderImpl>(V0Salt::from(salt.bytes)); + #[allow(clippy::indexing_slicing)] handle_map::get_dec_handle_map() .get(&handle.handle) .map(|cipher| { @@ -148,8 +149,10 @@ LdtAdvDecryptError::InvalidLength(_) => DecryptError::InvalidLength, LdtAdvDecryptError::MacMismatch => DecryptError::HmacDoesntMatch, }) - .map(|plaintext| { - data.copy_from_slice(plaintext.as_slice()); + .map(|(token, plaintext)| { + // slicing is safe: token and plaintext sum to data's len + data[..V0_IDENTITY_TOKEN_LEN].copy_from_slice(token.as_slice()); + data[V0_IDENTITY_TOKEN_LEN..].copy_from_slice(plaintext.as_slice()); SUCCESS }) })
diff --git a/nearby/presence/ldt_np_jni/java/LdtNpJni/src/test/java/com/google/android/gms/nearby/presence/hazmat/LdtNpJniTests.kt b/nearby/presence/ldt_np_jni/java/LdtNpJni/src/test/java/com/google/android/gms/nearby/presence/hazmat/LdtNpJniTests.kt index 07d29a3..e360599 100644 --- a/nearby/presence/ldt_np_jni/java/LdtNpJni/src/test/java/com/google/android/gms/nearby/presence/hazmat/LdtNpJniTests.kt +++ b/nearby/presence/ldt_np_jni/java/LdtNpJni/src/test/java/com/google/android/gms/nearby/presence/hazmat/LdtNpJniTests.kt
@@ -22,15 +22,15 @@ import org.junit.jupiter.api.assertThrows const val KEY_SEED = "CCDB2489E9FCAC42B39348B8941ED19A1D360E75E098C8C15E6B1CC2B620CD39" -const val HMAC_TAG = "DFB90A1F9B1FE28D18BBCCA52240B5CC2CCB5F8D5289A3CB64EB3541CA614BB4" +const val HMAC_TAG = "B4C59FA599241B81758D976B5A621C05232FE1BF89AE5987CA254C3554DCE50E" const val PLAINTEXT = "CD683FE1A1D1F846543D0A13D4AEA40040C8D67B" -const val SALT_BYTES = "32EE" -const val EXPECTED_CIPHER_TEXT = "04344411F1E57C841FE0F7150636BC782455059A" +const val SALT_BYTES = "0C0F" +const val EXPECTED_CIPHER_TEXT = "61E481C12F4DE24F2D4AB22D8908F80D3A3F9B40" class LdtNpJniTests { @Test fun roundTripTest() { - // Data taken from first test case in ldt_np_adv/resources/test/np_adv_test_vectors.json + // Data taken from ldt_ffi_test_scenario() val keySeed = KEY_SEED.decodeHex() val hmacTag = HMAC_TAG.decodeHex() val plaintext = PLAINTEXT.decodeHex() @@ -164,4 +164,4 @@ return chunked(2) .map { it.toInt(16).toByte() } .toByteArray() -} \ No newline at end of file +}
diff --git a/nearby/presence/ldt_np_jni/src/lib.rs b/nearby/presence/ldt_np_jni/src/lib.rs index e232c1e..334bcd9 100644 --- a/nearby/presence/ldt_np_jni/src/lib.rs +++ b/nearby/presence/ldt_np_jni/src/lib.rs
@@ -36,8 +36,8 @@ JNIEnv, }; -use ldt::XorPadder; -use ldt_np_adv::{LdtAdvDecryptError, LdtEncrypterXtsAes128, LdtNpAdvDecrypterXtsAes128}; +use ldt::{LdtCipher, XorPadder}; +use ldt_np_adv::{AuthenticatedNpLdtDecryptCipher, LdtAdvDecryptError, NpLdtEncryptCipher}; use np_hkdf::NpKeySeedHkdf; use crypto_provider_default::CryptoProviderImpl; @@ -56,10 +56,11 @@ /// Status code returned on successful cipher operations const SUCCESS: jint = 0; -type LdtAdvDecrypter = LdtNpAdvDecrypterXtsAes128<CryptoProviderImpl>; -type LdtAdvEncrypter = LdtEncrypterXtsAes128<CryptoProviderImpl>; +type LdtAdvDecrypter = AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl>; +type LdtAdvEncrypter = NpLdtEncryptCipher<CryptoProviderImpl>; /// Marker trait to ensure above types are thread safe +#[allow(dead_code)] trait JniThreadSafe: Send + Sync {} impl JniThreadSafe for LdtAdvDecrypter {} @@ -90,7 +91,7 @@ key_seed.as_slice().try_into().expect("Length is checked above"), ); - let cipher = LdtAdvEncrypter::new(&hkdf_key_seed.legacy_ldt_key()); + let cipher = LdtAdvEncrypter::new(&hkdf_key_seed.v0_ldt_key()); box_to_handle(cipher).map_err(|_| CREATE_ERROR) }) } @@ -221,14 +222,15 @@ })?; with_handle::<LdtAdvDecrypter, _, _>(handle, |cipher| { - let result = cipher + let (identity_token, plaintext) = cipher .decrypt_and_verify(buffer.as_mut_slice(), &expand_np_salt_to_padder(salt)) .map_err(|err| match err { LdtAdvDecryptError::InvalidLength(_) => DecryptError::DataLen, LdtAdvDecryptError::MacMismatch => DecryptError::MacMisMatch, })?; - let jbyte_buffer = bytes_to_jbytes(result.as_slice()); + let concatenated = &[identity_token.as_slice(), plaintext.as_slice()].concat(); + let jbyte_buffer = bytes_to_jbytes(concatenated); env.set_byte_array_region(&data, 0, jbyte_buffer) .map_err(|_| DecryptError::JniOp) @@ -301,7 +303,7 @@ /// Returns a XorPadder containing the HKDF of the salt. fn expand_np_salt_to_padder(np_salt: jchar) -> XorPadder<{ crypto_provider::aes::BLOCK_SIZE }> { let salt_bytes = np_salt.to_be_bytes(); - ldt_np_adv::salt_padder::<16, CryptoProviderImpl>(salt_bytes.into()) + ldt_np_adv::salt_padder::<CryptoProviderImpl>(salt_bytes.into()) } fn map_to_error_code<E: JniError, F: Fn() -> Result<jint, E>>(f: F) -> jint {
diff --git a/nearby/presence/np_adv/Cargo.toml b/nearby/presence/np_adv/Cargo.toml index 9b576a6..5a72ecd 100644 --- a/nearby/presence/np_adv/Cargo.toml +++ b/nearby/presence/np_adv/Cargo.toml
@@ -17,7 +17,7 @@ crypto_provider.workspace = true strum.workspace = true strum_macros.workspace = true -nom = { version = "7.1.3", default-features = false } +nom.workspace = true lazy_static.workspace = true sink.workspace = true tinyvec.workspace = true @@ -36,6 +36,7 @@ serde.workspace = true anyhow.workspace = true test_helper = { path = "../test_helper" } +test_vector_hkdf.workspace = true criterion.workspace = true crypto_provider_default = { workspace = true, features = ["std", "rustcrypto"] } np_ed25519 = { workspace = true, features = ["std"] }
diff --git a/nearby/presence/np_adv/benches/deser_adv.rs b/nearby/presence/np_adv/benches/deser_adv.rs index b52f53a..0cc553b 100644 --- a/nearby/presence/np_adv/benches/deser_adv.rs +++ b/nearby/presence/np_adv/benches/deser_adv.rs
@@ -21,34 +21,34 @@ clippy::panic )] -use core::marker::PhantomData; use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; -use crypto_provider::{CryptoProvider, CryptoRng}; +use crypto_provider::{ed25519, CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; -use ldt_np_adv::LegacySalt; +use ldt_np_adv::{V0IdentityToken, V0Salt, V0_IDENTITY_TOKEN_LEN}; +use np_adv::credential::matched::EmptyMatchedCredential; use np_adv::deserialization_arena; use np_adv::extended::serialize::AdvertisementType; +use np_adv::extended::V1IdentityToken; +use np_adv::legacy::serialize::UnencryptedEncoder; use np_adv::{ credential::{book::*, v0::*, v1::*, *}, - de_type::EncryptedIdentityDataElementType, deserialize_advertisement, extended::{ data_elements::{GenericDataElement, TxPowerDataElement}, deserialize::VerificationMode, serialize::{ - AdvBuilder as ExtendedAdvBuilder, MicEncryptedSectionEncoder, PublicSectionEncoder, - SectionBuilder, SectionEncoder, SignedEncryptedSectionEncoder, + AdvBuilder as ExtendedAdvBuilder, MicEncryptedSectionEncoder, SectionBuilder, + SectionEncoder, SignedEncryptedSectionEncoder, UnencryptedSectionEncoder, }, }, legacy::{ - actions::{ActionBits, ActionsDataElement}, - serialize::{AdvBuilder as LegacyAdvBuilder, LdtIdentity}, - ShortMetadataKey, + data_elements::actions::{ActionBits, ActionsDataElement}, + serialize::{AdvBuilder as LegacyAdvBuilder, LdtEncoder}, }, - shared_data::{ContextSyncSeqNum, TxPower}, - MetadataKey, PublicIdentity, + shared_data::TxPower, }; +use np_hkdf::{DerivedSectionKeys, NpKeySeedHkdf}; use rand::{Rng as _, SeedableRng as _}; use strum::IntoEnumIterator; @@ -67,42 +67,40 @@ ), |b| { let identities = (0..num_identities) - .map(|_| V1Identity::random(&mut crypto_rng)) + .map(|_| V1Identity::random::<CryptoProviderImpl>(&mut crypto_rng)) .collect::<Vec<_>>(); let mut adv_builder = ExtendedAdvBuilder::new(AdvertisementType::Encrypted); // take the first n identities, one section per identity for identity in identities.iter().take(num_sections) { - let broadcast_cm = SimpleSignedBroadcastCryptoMaterial::new( + let broadcast_cm = V1BroadcastCredential::new( identity.key_seed, - identity.extended_metadata_key, - identity.key_pair.private_key(), + identity.identity_token, + identity.private_key.clone(), ); match identity_type { VerificationMode::Mic => { let mut sb = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Private, &broadcast_cm, )) .unwrap(); add_des(&mut sb); - sb.add_to_advertisement(); + sb.add_to_advertisement::<CryptoProviderImpl>(); } VerificationMode::Signature => { let mut sb = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Private, &broadcast_cm, )) .unwrap(); add_des(&mut sb); - sb.add_to_advertisement(); + sb.add_to_advertisement::<CryptoProviderImpl>(); } } } @@ -112,7 +110,7 @@ run_with_v1_creds::< CryptoProviderImpl >( - b, crypto_type, identities, adv.as_slice() + b, crypto_type, identities, adv.as_slice(), ) }, ); @@ -126,10 +124,10 @@ c.bench_function("Deser V1 plaintext: sections=1", |b| { let mut adv_builder = ExtendedAdvBuilder::new(AdvertisementType::Plaintext); - let mut sb = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut sb = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); add_des(&mut sb); - sb.add_to_advertisement(); + sb.add_to_advertisement::<CryptoProviderImpl>(); let adv = adv_builder.into_advertisement(); @@ -157,20 +155,16 @@ let identity = &identities[0]; - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new( - identity.key_seed, - identity.legacy_metadata_key, - ); + let broadcast_cm = + V0BroadcastCredential::new(identity.key_seed, identity.identity_token); let mut adv_builder = - LegacyAdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - EncryptedIdentityDataElementType::Private, - LegacySalt::from(rng.gen::<[u8; 2]>()), + LegacyAdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new( + V0Salt::from(rng.gen::<[u8; 2]>()), &broadcast_cm, )); - let mut action_bits = ActionBits::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(3).unwrap()); + let action_bits = ActionBits::default(); adv_builder.add_data_element(ActionsDataElement::from(action_bits)).unwrap(); let adv = adv_builder.into_advertisement().unwrap(); @@ -188,10 +182,9 @@ } pub fn deser_adv_v0_plaintext(c: &mut Criterion) { - let mut adv_builder = LegacyAdvBuilder::new(PublicIdentity); + let mut adv_builder = LegacyAdvBuilder::new(UnencryptedEncoder); - let mut action_bits = ActionBits::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(3).unwrap()); + let action_bits = ActionBits::default(); adv_builder.add_data_element(ActionsDataElement::from(action_bits)).unwrap(); let adv = adv_builder.into_advertisement().unwrap(); @@ -227,16 +220,16 @@ fn run_with_v0_creds<C>( b: &mut Bencher, crypto_material_type: CryptoMaterialType, - identities: Vec<V0Identity<C>>, + identities: Vec<V0Identity>, adv: &[u8], ) where C: CryptoProvider, { let mut creds = identities .into_iter() - .map(|identity| identity.into_discovery_credential()) - .map(|discovery_credential| MatchableCredential { - discovery_credential, + .map(|identity| identity.into_discovery_credential::<C>()) + .map(|crypto_material| MatchableCredential { + discovery_credential: crypto_material, match_data: EmptyMatchedCredential, }) .collect::<Vec<_>>(); @@ -283,16 +276,16 @@ fn run_with_v1_creds<C>( b: &mut Bencher, crypto_material_type: CryptoMaterialType, - identities: Vec<V1Identity<C>>, + identities: Vec<V1Identity>, adv: &[u8], ) where C: CryptoProvider, { let mut creds = identities .into_iter() - .map(|identity| identity.into_discovery_credential()) - .map(|discovery_credential| MatchableCredential { - discovery_credential, + .map(|identity| identity.into_discovery_credential::<C>()) + .map(|crypto_material| MatchableCredential { + discovery_credential: crypto_material, match_data: EmptyMatchedCredential, }) .collect::<Vec<_>>(); @@ -333,6 +326,7 @@ } } } + fn add_des<I: SectionEncoder>( sb: &mut SectionBuilder<&mut np_adv::extended::serialize::AdvBuilder, I>, ) { @@ -348,51 +342,61 @@ ); criterion_main!(benches); -struct V0Identity<C: CryptoProvider> { +struct V0Identity { key_seed: [u8; 32], - legacy_metadata_key: ShortMetadataKey, - _marker: PhantomData<C>, + identity_token: V0IdentityToken, } -impl<C: CryptoProvider> V0Identity<C> { +impl V0Identity { /// Generate a new identity with random crypto material fn random<R: rand::Rng + rand::CryptoRng>(rng: &mut R) -> Self { Self { key_seed: rng.gen(), - legacy_metadata_key: ShortMetadataKey(rng.gen()), - _marker: PhantomData, + identity_token: V0IdentityToken::from(rng.gen::<[u8; V0_IDENTITY_TOKEN_LEN]>()), } } /// Convert this `V0Identity` into a V0 discovery credential. - fn into_discovery_credential(self) -> V0DiscoveryCredential { - SimpleBroadcastCryptoMaterial::<V0>::new(self.key_seed, self.legacy_metadata_key) - .derive_v0_discovery_credential::<C>() + fn into_discovery_credential<C: CryptoProvider>(self) -> V0DiscoveryCredential { + let hkdf = NpKeySeedHkdf::<C>::new(&self.key_seed); + V0DiscoveryCredential::new( + self.key_seed, + hkdf.v0_identity_token_hmac_key().calculate_hmac::<C>(self.identity_token.as_slice()), + ) } } -struct V1Identity<C: CryptoProvider> { +struct V1Identity { key_seed: [u8; 32], - extended_metadata_key: MetadataKey, - key_pair: np_ed25519::KeyPair<C>, + identity_token: V1IdentityToken, + private_key: ed25519::PrivateKey, } -impl<C: CryptoProvider> V1Identity<C> { +impl V1Identity { /// Generate a new identity with random crypto material - fn random(rng: &mut C::CryptoRng) -> Self { + fn random<C: CryptoProvider>(rng: &mut C::CryptoRng) -> Self { Self { key_seed: rng.gen(), - extended_metadata_key: MetadataKey(rng.gen()), - key_pair: np_ed25519::KeyPair::<C>::generate(), + identity_token: rng.gen(), + private_key: ed25519::PrivateKey::generate::<C::Ed25519>(), } } /// Convert this `V1Identity` into a `V1DiscoveryCredential`. - fn into_discovery_credential(self) -> V1DiscoveryCredential { - SimpleSignedBroadcastCryptoMaterial::new( + fn into_discovery_credential<C: CryptoProvider>(self) -> V1DiscoveryCredential { + let hkdf = NpKeySeedHkdf::<C>::new(&self.key_seed); + + V1DiscoveryCredential::new( self.key_seed, - self.extended_metadata_key, - self.key_pair.private_key(), + hkdf.v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + hkdf.v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + hkdf.v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + self.private_key.derive_public_key::<C::Ed25519>(), ) - .derive_v1_discovery_credential::<C>() } }
diff --git a/nearby/presence/np_adv/resources/test/mic-encrypted-test-vectors.json b/nearby/presence/np_adv/resources/test/mic-encrypted-test-vectors.json deleted file mode 100644 index a7834ec..0000000 --- a/nearby/presence/np_adv/resources/test/mic-encrypted-test-vectors.json +++ /dev/null
@@ -1,2295 +0,0 @@ -[ - { - "adv_header_byte": "20", - "aes_key": "F3DB017C70E08EC5178C92F3AEA0C362", - "data_elements": [ - { - "contents": "CF75D23EDA8F6E4A23", - "de_type": 383 - }, - { - "contents": "731B76151735869205CC41", - "de_type": 73 - }, - { - "contents": "7C2A8DE86B2CBB997703", - "de_type": 228 - }, - { - "contents": "99F5163DCA0BB9BE89755A6C5AB321", - "de_type": 446 - } - ], - "encoded_section": "6D91100056F596D16E1F87B107EE86102FFC6D5E9002F00C41CDDF533667362CD14AC54A9388FA3D30AA7CA6603071B8B0FA19BF582479F773F1C7D0EADF98E98B9447139F244D571B780475ACD9CB248F33B2C085925213360732D44081C27CA6EB40BD8A626BC776D88C5FDB09", - "identity_type": "trusted", - "key_seed": "F0ED9126768CE7DC685FF74932AC5A876442C4E42359A43F720A575142A45043", - "metadata_key": "45795EE4C6533A830886E2C5885EB9E5", - "nonce": "40E95D525FAEA1C1FEE39A8E", - "section_mic_hmac_key": "A22386E85112EF883218A5B75669B7102E017E9AA149F408A079F60B1D14B4F4", - "section_salt": "56F596D16E1F87B107EE86102FFC6D5E" - }, - { - "adv_header_byte": "20", - "aes_key": "F076F2B4FA1F3704DDC4EC5CD60C4657", - "data_elements": [ - { - "contents": "B62889", - "de_type": 72 - }, - { - "contents": "68FDB8895CB7ABCF18390616113107B73321A905D22FDB99", - "de_type": 175 - }, - { - "contents": "D5A173DC337EFA759D443C50F14F25AC18A06D44C4", - "de_type": 354 - } - ], - "encoded_section": "6D911000CB9C39FAF5D89CEF1FD7E313DC2F95D79004919332D945C714DE3B58B0762E7F9378D80F35D0DE1E8BD321656B270EA3379F029FB09E44AAFB091B0678A0AB69B055CCE5C2F576EAE52DAC0D6C11FD6A878ABF337B9647FF259ED24F5687641E8ED13A612810F22EC240", - "identity_type": "provisioned", - "key_seed": "907E34F78FBC8CA40FCA224C12B95BA2C4A0148BA0D19BDADEE1798579EF7D35", - "metadata_key": "B524D8ABD8E7DCFD13CE922F2FD9EFAC", - "nonce": "AD0AC7BE3A89262786A55139", - "section_mic_hmac_key": "690542812A39DB48DD638AED6021A250767F79604C638E361A8F7F5FE92C5E40", - "section_salt": "CB9C39FAF5D89CEF1FD7E313DC2F95D7" - }, - { - "adv_header_byte": "20", - "aes_key": "B9549633BA2531AEF16D592815C12269", - "data_elements": [ - { - "contents": "BA", - "de_type": 79 - }, - { - "contents": "796F131D0D034508", - "de_type": 141 - }, - { - "contents": "0245", - "de_type": 522 - } - ], - "encoded_section": "48911000897E4DB6C940976334871B64811D8379900416AC9B5760E31F037634EED3B9C81AEF75B5134E7065DCEFF8CF3197BD2242BE4E29384125B35FB9A4BB7D4D1A650F1E30DBA3", - "identity_type": "provisioned", - "key_seed": "E66AECA540D070C5E430CE461A3E209F0650AAF3E69CC79C20935DEA3D468A46", - "metadata_key": "B2AC31CB7B88B7FA165B5E41AE706E04", - "nonce": "E3CB89790FEA866E19F4926A", - "section_mic_hmac_key": "EE72E920E379F06879BD8AED8EF9BF8D5903E5CF94A83815929260521F84C17C", - "section_salt": "897E4DB6C940976334871B64811D8379" - }, - { - "adv_header_byte": "20", - "aes_key": "088B6339D6D727E797DD1EA3EAC999B3", - "data_elements": [ - { - "contents": "DDCCC496B0BE050B7607", - "de_type": 850 - } - ], - "encoded_section": "429110008F292492B012ACE2C0EF4F25E0901F9490022CF669461319C1165AA131A7BF2835C97FC3ECD77522FB93CE0675D0313D7AB03E230DBE46E286192CD451E9FF", - "identity_type": "trusted", - "key_seed": "CB61506281210764CE5E3504BF3A41AF69196369375BFE16245B0CA19421650D", - "metadata_key": "B9696864507A1DC2EF99DF5441AD25EF", - "nonce": "9CC88703DA8A3C82DA5DF32D", - "section_mic_hmac_key": "8DE5B98089EEEAB5ABB079EE0C6C8F37289CFCDA74B81BE4F3599EA7F10B3A3C", - "section_salt": "8F292492B012ACE2C0EF4F25E0901F94" - }, - { - "adv_header_byte": "20", - "aes_key": "142EF4EFAA03C54D43958647B4A9053A", - "data_elements": [ - { - "contents": "B8E42416CD4B3281EE2EDB1B36B89DFD17D35C46B354D6", - "de_type": 441 - }, - { - "contents": "72787349FDC162A25D13BA", - "de_type": 664 - }, - { - "contents": "E0A29FC658F199AFF9", - "de_type": 308 - }, - { - "contents": "8859EB742D3B433BD0F992285B9EEAA1", - "de_type": 319 - } - ], - "encoded_section": "7C911000DFCC6FC56956B0D99F2F29682117B0759004E48F8DE2D74AC7FEAFBEA42F808B4DCE7D17F2841097DA561701AF9F365BA4F702A4CA79D40F6F88C383487B6524BFACDDF294D2DE20CCD7B2BF3A765598144323933CEAD4C1A5C6522A867A5BFDF562A43C537A50A3987AB4F9AE446043117F7A20E1C41B398F", - "identity_type": "provisioned", - "key_seed": "311F871B4605A04B3310C13D7297AEE745EE105A5D116D05B114A39C2DE27B85", - "metadata_key": "18C51BF65C261CFB2F8106AA4C8476B6", - "nonce": "1F562F760A35CE9445D40B28", - "section_mic_hmac_key": "6F25A84CB39DACD4B9DC7BB4354EE7BB268FBB559121D0F530BE2FDC212C7478", - "section_salt": "DFCC6FC56956B0D99F2F29682117B075" - }, - { - "adv_header_byte": "20", - "aes_key": "0C3C901C96C81D5822A42886F20E4D24", - "data_elements": [ - { - "contents": "", - "de_type": 437 - } - ], - "encoded_section": "38911000B3AF643914DD58250EF9795F77B0FA3B90018EACECB07EEC9E2E72550CB8C373FB6EDA5F1CAF378E19C6207AE3C6F7CDA7E1321B56", - "identity_type": "private", - "key_seed": "39739EA99CFB0EF8200B08C12213FB3370A4DFB58CEADA17764FBCA9FC05B914", - "metadata_key": "A1F9BE98BF2BE21F318FF60776ECF594", - "nonce": "E067B8B38B20F64D35EE4B1C", - "section_mic_hmac_key": "DB710921FA3969941C33329A0FC10AED0EB49A7BEA627ABBAB6E4BBBF6886478", - "section_salt": "B3AF643914DD58250EF9795F77B0FA3B" - }, - { - "adv_header_byte": "20", - "aes_key": "0DFF79575A76A69E5545F23F2D568BF5", - "data_elements": [ - { - "contents": "8D530D2FF57D6A089257EEA03F2643CCF76DF103", - "de_type": 739 - }, - { - "contents": "88E7ABACA5E9", - "de_type": 563 - }, - { - "contents": "9CA636C900FFAEB51060B40D1E60D751840CA3", - "de_type": 831 - }, - { - "contents": "8AC0EC13CB0B", - "de_type": 944 - }, - { - "contents": "4FD1B972DDA8376DF7181799B3AEC3D4FA3875CDA0B9F2A244085CDD72", - "de_type": 263 - } - ], - "encoded_section": "94911000A089A545FC2F1E048CCFEFF6FC7530BA9002D0BA12200150BF15A06427841CC00E9CC99FC3032DDB93D46A96DEC5F92DD89849328418BB27225CA77542A2BBDE1896CF76D0143EA351786BC3DB40228363971552E8CB5BF440F6B6569B610D0F09B6E6B46922D86E1DB35A2AE0507A10268AD4077867FF55C7286971DB6BF27D01B68BEF04B9FE12FF660A0ECE154D2B27", - "identity_type": "trusted", - "key_seed": "5CE70AB764EE544F6A9B48791033EDB78D6541368BE2A02C41C93BEE27645D15", - "metadata_key": "29F72458A212E09F3E13A14D927CBB97", - "nonce": "C6002C4E093E3ACD57A0DA8A", - "section_mic_hmac_key": "BF94C21240800483EE76C69F94D1E7E867EFC9AB11CE74E672C936634C0F7883", - "section_salt": "A089A545FC2F1E048CCFEFF6FC7530BA" - }, - { - "adv_header_byte": "20", - "aes_key": "048C8515B3970ACA7E06DD671E758AB7", - "data_elements": [ - { - "contents": "672D400589BB794E2A33DE53A62FF97458DAC28DF015F304CE9EBCE8CF", - "de_type": 502 - }, - { - "contents": "C2D9DC3F76FC72BE4BF7D3AFF43B1041B0BC93512BF73ADA95EDC4", - "de_type": 692 - }, - { - "contents": "B010CC19D7FB", - "de_type": 129 - } - ], - "encoded_section": "7C91100095FFF79474626138B7A9200A474C449F900259C6F85AD235549231775D62E7E710EA91D16662378B15BD5C34B7D14543BB5F289B37E17599C0AF6572A0630356ECA030870CAE9697E92FA9BB0632BE009F643C018B1571592CB0750C158BE299806D0673779B000E047CF4E4D8BD732544EDE5C6CBB4F71E05", - "identity_type": "trusted", - "key_seed": "9F52A2F6A5F571B558151E84D8965C427733005A6CD580E66B5C398443BB7479", - "metadata_key": "4C95AE9955DE9A3684F52B00461035BF", - "nonce": "33CA4805B89AE4F80DB67BE3", - "section_mic_hmac_key": "4BC7E7FC685A2E3D9EC90B20014586C986E3054B456EC2851E6606AEDC3955EA", - "section_salt": "95FFF79474626138B7A9200A474C449F" - }, - { - "adv_header_byte": "20", - "aes_key": "4C9F52374665C592601F5B2BD404B94A", - "data_elements": [ - { - "contents": "91EAFB7D", - "de_type": 663 - }, - { - "contents": "22027014F8D43A605E0C179A1E144A3058D7C024359E7A42B83DBA9B0F", - "de_type": 163 - }, - { - "contents": "0830ACBE1994FB", - "de_type": 291 - } - ], - "encoded_section": "669110005723CCC591C04732B131D258FB5C9A219002E345F42E0D2D02EF57D890EE70F4A95BFE4C9651BF6E2067BD6707820636D5E484F9D519029D86290ECC42C846AF1D0C8D03BD155D791F47637F9F698A8B9D71E261712DE1F1219ED87F7F2045BC240A41", - "identity_type": "trusted", - "key_seed": "1D02A26B11FB561BD54036A1FA2B325E74D226CA72428C391650E5249B40E0E9", - "metadata_key": "702C35764676569F45279BE0BA2F941D", - "nonce": "08838921E1C57E275B554B1E", - "section_mic_hmac_key": "163F7952B1866F16C0E5CD3CA950D786E53F04C7CEEBA1946AD76C16185F52FD", - "section_salt": "5723CCC591C04732B131D258FB5C9A21" - }, - { - "adv_header_byte": "20", - "aes_key": "A3034AE0322F5E77ED6B21B5E5368108", - "data_elements": [ - { - "contents": "537F96FD94E13BE589F0141145CFC0EEC4F86FBDB2", - "de_type": 571 - }, - { - "contents": "D301FFB24B5B", - "de_type": 541 - }, - { - "contents": "EA95F07C25B75C04E1B2B8731F6A55BA379FB141", - "de_type": 51 - }, - { - "contents": "2EFD3101E2311BBB108F0A7503907EAF0C2EAAA60CDA8D33A294C4CEACE0", - "de_type": 729 - }, - { - "contents": "B0", - "de_type": 411 - } - ], - "encoded_section": "91911000DE2A89ED98474AF3E41E48487E8AEBDE90014C18BCB9F9AAC5C11A1BE00A10A5DCD2C49A74BEBAF0FE72FD5053B9DF8B9976C80BE0DCE8FEE83F1BFA9A89EB176CA48EE4ED5D15C6CDAD6B9E41187AA6316D7BFD8E454A53971AC00836F7AB0771FF0534050037D49C6AEB18CF9F8590E5CDEE2FBC330FCDC640C63F0735B7E3F02FE61A0496EF976A158AD3455D", - "identity_type": "private", - "key_seed": "959D2F3CAB8EE4A2DEB0255C03762CF5D39EB919300420E75A089050FB025E20", - "metadata_key": "EF5E9A0867560E52AE1F05FCA7E48D29", - "nonce": "23B64C2B1724E5AE9528FCD4", - "section_mic_hmac_key": "2F1B12002184860A496B2DF7FB743401BA8E8BC5F22F661BAD69335E99DB8A19", - "section_salt": "DE2A89ED98474AF3E41E48487E8AEBDE" - }, - { - "adv_header_byte": "20", - "aes_key": "15AB0E1BF3C908D5A92C9A52158DAC00", - "data_elements": [], - "encoded_section": "35911000172C7E49FB61097603390278AA4B48F8900477935610288681FDC9B7250022F01CFA66E59183F392C5C2485D8240ABC96D15", - "identity_type": "provisioned", - "key_seed": "C1FE7DD8760BDC37EEED65E07FF3F9DB9B2DA247260038675679921566A4466C", - "metadata_key": "D84140E3576B04F8D9290744C62D20A1", - "nonce": "A8FD0BF085BA1C3E8A23FC0C", - "section_mic_hmac_key": "3BBF201D9180707DDF5DA4321B477A2D0CFEFC00D72EE560F0E41B5178315366", - "section_salt": "172C7E49FB61097603390278AA4B48F8" - }, - { - "adv_header_byte": "20", - "aes_key": "2C8D685B3ED53CA46D6A6AC126596C84", - "data_elements": [ - { - "contents": "E95043396FF5CE7FEA272F1E9D8A", - "de_type": 359 - } - ], - "encoded_section": "46911000B9EB78D15B9493668E3506DD9E7A2DEC9001884E76187E89CB0107A5090D664508854DCF8722E98904E6BB57422710F3CBB3271A743BAE59467EED31F62B714060F040", - "identity_type": "private", - "key_seed": "0C43A03CC43B6536086910E73F4499C368BE47235FEA439124005FD91047C8DD", - "metadata_key": "6B8DFEAC098F9DD035F14843C3196CC8", - "nonce": "920205C1FC28E58575E08D47", - "section_mic_hmac_key": "5FE0D08732D5615AE4447E726DEAB0083D9458E66DAE596377DDC103C34A4442", - "section_salt": "B9EB78D15B9493668E3506DD9E7A2DEC" - }, - { - "adv_header_byte": "20", - "aes_key": "C56F4750DBCFE87ADD8E2159B3EB5646", - "data_elements": [ - { - "contents": "148ADAFBA927A9A3D361CB34792A1FD1311A", - "de_type": 16 - }, - { - "contents": "37215F", - "de_type": 776 - }, - { - "contents": "5B75B7A4044E3100635709818ECB099706", - "de_type": 563 - }, - { - "contents": "4A70F7FE36FC", - "de_type": 49 - } - ], - "encoded_section": "6B91100010510FF96F9DE71AFB125A00637D9A159002692F0CA5C9AD242760DFCCB7F9E445AB0545ABDD91DBB4E6A7DCAE21ABF58D01CC3C1B95AF9442EDF2FA1ED5C551FABF071981137AFB04F4B67F13D43CAA959F53819A4B90913C7CD4B945665E74898BDEEA50939FA6", - "identity_type": "trusted", - "key_seed": "18D77C2D69389B38F6430DECF46D34893C188EDF6F57E306BD159A441D602D68", - "metadata_key": "0DFE12776B497E72E415E41625C4A2A4", - "nonce": "A25A744723723AB492153CE9", - "section_mic_hmac_key": "B1BC6C3AC220AF74BAC5EA8A85692095575FA6C2172ED9E66669114164BF55E1", - "section_salt": "10510FF96F9DE71AFB125A00637D9A15" - }, - { - "adv_header_byte": "20", - "aes_key": "3BDA27AEC19E0135552AD5ABB02C45D2", - "data_elements": [ - { - "contents": "92F73CEBBE55EFF2391445A2B96299155B78", - "de_type": 984 - }, - { - "contents": "8C4615561E9CF7589FA8E6F7B57893025DF55C", - "de_type": 919 - }, - { - "contents": "DDF6FEBA14ABB1B094A277D361A8C70B988E1010534FAFDF25", - "de_type": 676 - }, - { - "contents": "8650458E65DE07BFFCD2EC46E0D4D05609A66D9AB777FA341EFE3280A5AC", - "de_type": 784 - } - ], - "encoded_section": "9D911000D86DFF361F5567606CCBAD126A86C01390028E06467447060E4E27C066C5B7F8B785D2476A0FFACC9C85C1E2211B7609D8A4A2C7036F982F923D1DFCF0161B60A3AA5DE2287B909FABE3E902EF1CCD45AB7D9CACE4FAB3C05CB9A00FCC5AD93E9E3B2B31A2ECC226D2209BF24FC7D13D0AE53C912D03DF47F1A4C132BF949C555E8D35436011B852DDB228F4964483F820DA360FFC9506087F99", - "identity_type": "trusted", - "key_seed": "A6915F7F275F268563F06B70294DE268F4C8FE2ED64831049F5071DD2D7AFF7F", - "metadata_key": "29B703C99077654D9EC2BD86066D3CC5", - "nonce": "ED125BA0057DCFEB89ED7190", - "section_mic_hmac_key": "1B8F822A197030498D51E0F2E4B9C7C306074D7C83C73CAE508D2FFA46EB743A", - "section_salt": "D86DFF361F5567606CCBAD126A86C013" - }, - { - "adv_header_byte": "20", - "aes_key": "9E629E04812454CB600A54C8837CC057", - "data_elements": [ - { - "contents": "C1B396A29B6967ECF8673E009B2E7F94C4DECD7FA20C176EA0AD98B9", - "de_type": 253 - }, - { - "contents": "3FFEC56E8DB922CD8C5AB5E47452E571", - "de_type": 605 - } - ], - "encoded_section": "67911000229151F0CBA214F520EFDBF30FB4DA43900287511210A4AF78894FA1DEE707C412015D271BEE2789F49BB5DC67D44E5B9E58B6421F4C834D13F29940800D31315840591BD869F1C2D2887914627DE54D90AA254C6CE1699AA9CA7198ADD71BDC46D91117", - "identity_type": "trusted", - "key_seed": "1C9A55E064B78E94CB6B070F433CA94D21CB3318E048A7A2CAA83FF958419794", - "metadata_key": "1A240C90D7E260458660C8B07F991AE6", - "nonce": "2BEB4BC7C05434ABBA19E538", - "section_mic_hmac_key": "050D12FF03D51C57EC4AE018EDC1896C38226E1A0481362E415CCB28F5A01B5D", - "section_salt": "229151F0CBA214F520EFDBF30FB4DA43" - }, - { - "adv_header_byte": "20", - "aes_key": "8C996EFAD07DDDED26DFDF98812CA923", - "data_elements": [ - { - "contents": "B7C019E21BDE02221C04A4", - "de_type": 43 - } - ], - "encoded_section": "42911000D1662A41EA8D74EEDE6BE6686D41414E90029CE0D1823D6C861F9B05C79235D6C1CB99634640B9BA98F7B3C72B67F242E2E40E36C937F671A88D63FF97C4C4", - "identity_type": "trusted", - "key_seed": "2027245C1810377C3846FFC4F33A46FD5F55BEFBB13C9EB07D7D5AD3CFAB48B4", - "metadata_key": "9F4AD9EDF0A6CAAD2E9E99871E4CE52C", - "nonce": "A71E97EBB5FEF5C10118B443", - "section_mic_hmac_key": "3BEFA04D9C10EC14E050D8106803C71F788E338E191EDFA21FC2029FE1A90922", - "section_salt": "D1662A41EA8D74EEDE6BE6686D41414E" - }, - { - "adv_header_byte": "20", - "aes_key": "AE8C6F011FE35C9C96FE8EBDE339A41F", - "data_elements": [ - { - "contents": "607A867B3B29B89041F9", - "de_type": 979 - }, - { - "contents": "5E799499", - "de_type": 25 - }, - { - "contents": "92CB515B79EDD5E37C12C6B5864DF420AF7DDE1B5919331DA7", - "de_type": 577 - } - ], - "encoded_section": "649110008A4AF96D2B686F8C79E0133C7A1300D39001533E4A9492889398E4BEA2572B455C201BE24382C5D0FCEF256113AA7541173BBC6A2B9AFC3CB2A133424BA12055069603174E36F3407444B5FBFA5BFAE8C8B6BD893AB31B9D869105014A931AEA10", - "identity_type": "private", - "key_seed": "F728E206C88A47D4C5063BBF54C218435A04B921E3D0E2774572D88024076D7E", - "metadata_key": "CD8451667D7BBD7EB4CD5E456ECF8167", - "nonce": "3F7D4273CDA786C66C557ADC", - "section_mic_hmac_key": "82B0C8B8007802CE1CCF367F07830FDAD2401C8EB5849613602E568E634DAFB4", - "section_salt": "8A4AF96D2B686F8C79E0133C7A1300D3" - }, - { - "adv_header_byte": "20", - "aes_key": "9078B570449046A4C6FD9246ABE3E17E", - "data_elements": [ - { - "contents": "381690D8CB5DE6CB", - "de_type": 724 - }, - { - "contents": "905EB45FAD", - "de_type": 144 - }, - { - "contents": "969FEFE0", - "de_type": 302 - }, - { - "contents": "75202C93DD512023EFD3EBF3", - "de_type": 742 - } - ], - "encoded_section": "5E911000F765D4EE37755137F6B7AF43D4ECF2CB9002361BF7AEC5BEA9E0F9790E737E559951EB09254D0B4304A81E21FF7C9B463A8AF4D29B35B6B909C255286B707B85F028D277148C6A82877695FF915BD0602946C37F4AAF6C1C315B98", - "identity_type": "trusted", - "key_seed": "DD3AB1ADE4D985E6D6E67F2FE19DD6A75A9F5B4560CD3C05FAFF8A88C283AB3F", - "metadata_key": "D53DBD8613161F1527385E5F27FEE124", - "nonce": "D30A2D8CEFAB8C91E0B1799D", - "section_mic_hmac_key": "EDFA40290EB30E6669C551947A061A587843CCE47F4620E51ABA239AB79AA739", - "section_salt": "F765D4EE37755137F6B7AF43D4ECF2CB" - }, - { - "adv_header_byte": "20", - "aes_key": "C2FF97FBAB946B17D2BD0CA0712FA7DB", - "data_elements": [ - { - "contents": "B0F9DF275D2D5A37C95B9CC9AB", - "de_type": 114 - } - ], - "encoded_section": "44911000EB645DE61C9BB4C40BC585AABA223BAA9004B40CE842866C9F317B5C429C501392E13495FA18E48C34BDABF4152C8E98E90ED1AFD11BCABD4EF60CBA9347FB0120", - "identity_type": "provisioned", - "key_seed": "CAB68F8D497B54A0B25EE602EDC659B8C12F9E9E49EC8FC2C2487E8FA955E606", - "metadata_key": "CDCE54153DA53A283DBF35F0D456FBDF", - "nonce": "D7FA723581DFA37F8CD7F284", - "section_mic_hmac_key": "EECDEE6DCC125C40BD1002DFBAA77C8D5F16D6A9D152E6524A13E213F5CDA36A", - "section_salt": "EB645DE61C9BB4C40BC585AABA223BAA" - }, - { - "adv_header_byte": "20", - "aes_key": "BD5FFED9F8FF99EFD9276BAE103C8520", - "data_elements": [ - { - "contents": "A9F592F1DCA1C71CCF03CC0310DF337C9A", - "de_type": 683 - }, - { - "contents": "E18AD6552B4C", - "de_type": 277 - } - ], - "encoded_section": "52911000A798801A6B6BB3B3CE199A04C6D39C749002F4A793DDD478205BE47B9D5A3D02821CFECD82A205E596D82F1CA5F52DFD12D2F160C20332DD75B56CFF48AFC079B80AB8151D3FC020D71FF03A220692", - "identity_type": "trusted", - "key_seed": "9DA9C8ADB2F20D379E5C103E92D60D4ACC946AD0DC57B08E71A6CAF174DE27FD", - "metadata_key": "32044EF9F7B354E253E7206AC19172BC", - "nonce": "FD61DCBF349648F6BCAD5FF7", - "section_mic_hmac_key": "CEF13D97D862C57A7CC2ED89FA453B5F331A39B46EF3DAED677C6354FCF41A99", - "section_salt": "A798801A6B6BB3B3CE199A04C6D39C74" - }, - { - "adv_header_byte": "20", - "aes_key": "AB8FC3047B5D459C0FE3A8D32DA1D396", - "data_elements": [ - { - "contents": "70E9867134E018A407BFFA11681FE66225551030", - "de_type": 694 - } - ], - "encoded_section": "4C911000F340B13BAF10C096314AD12554265BA69004D98C2427C11201067AAA42C262F78315F0FBD68F03CA256E74CD74CC39E3B0399E41E8DC766AB30241498364F94C204BA6F1D12C66C752", - "identity_type": "provisioned", - "key_seed": "9E50221DB4D19E3E2E6E0D61F2FE4FD765B0AB77D795B8BF9DEE945C9258D90F", - "metadata_key": "E59AB0FB0471EDE9516038F2B830FC8D", - "nonce": "D547910B27183848271E093E", - "section_mic_hmac_key": "0C67958E203428FCD8B023C2C97BEFD62A64E72DC0F3F9078AE494DA235E4E80", - "section_salt": "F340B13BAF10C096314AD12554265BA6" - }, - { - "adv_header_byte": "20", - "aes_key": "5E155066D56083328A063FBD5AFBF1CE", - "data_elements": [ - { - "contents": "B2E8AD80552E7D", - "de_type": 638 - }, - { - "contents": "EBA00821E05107D40E6B3CAB8E86027D497F34670527D1D6", - "de_type": 337 - }, - { - "contents": "549E6C2D1425", - "de_type": 826 - } - ], - "encoded_section": "63911000A847D51D7D049D481D63F14F4A8D01099002FC5925A9E42B41321E56021A3D01157DC10E00CFF86A66638C7313814DF85E2E050AC4235DE9634416B34AAEC4419D9F50D49952742723228FA5CC8A8981C6E5E71904FE5FDAD5111C3C81C88E65", - "identity_type": "trusted", - "key_seed": "BE5027936C60695FF4EA18AC1F81078221C50A8C22C98F36C9A5877D369E4000", - "metadata_key": "1B43759002C9095970DB092A0086FECF", - "nonce": "CCA806551E3DE4A2C7015C4F", - "section_mic_hmac_key": "B8C388D47A6B125B3E637DBE4281824A170687F5D596510B94A95DFBD0420A5F", - "section_salt": "A847D51D7D049D481D63F14F4A8D0109" - }, - { - "adv_header_byte": "20", - "aes_key": "BA3816EAD76DAC246880A27F137D4CC2", - "data_elements": [ - { - "contents": "3909A77A6295", - "de_type": 706 - }, - { - "contents": "A360F1", - "de_type": 563 - }, - { - "contents": "9B77E78C7CB64198BC2E5E676080B8652C88A3F1A71B5B62CC5B87", - "de_type": 496 - }, - { - "contents": "DD4080284EEF0BFBA61283376C7A", - "de_type": 129 - }, - { - "contents": "D3", - "de_type": 362 - } - ], - "encoded_section": "7791100034A1CA42CE8D750265DD13710E6AA8F390024301C25BBA38E693BCF7834E08B62F4B4569EC8704250959F6EEE5971C2E25BB63EF65C1CA1B20917A433DAA9379ADB3773F463BC8A81A938CB83EA4E1BBF4CB1A4409D38E9511B4660A5C5458337CCBD98AA3E3A41D88C98ED0A9D8AE27F28206D0", - "identity_type": "trusted", - "key_seed": "7052FBAFC59D8ED636F51F254C3E8D2429604C2A58A3A0A27C54C2D83B4D4353", - "metadata_key": "0230CE096D5CBE15B55F65F270D0D411", - "nonce": "51FD2C7EBA743483252DA523", - "section_mic_hmac_key": "C1941723E73EE200B78932065A479E2380FBEE95082846C9FEEDA9D35C13E84E", - "section_salt": "34A1CA42CE8D750265DD13710E6AA8F3" - }, - { - "adv_header_byte": "20", - "aes_key": "3F7BAA4E9ADF649F68504D2BADC49E59", - "data_elements": [ - { - "contents": "C7CD03AABE413B68D38D5528B8", - "de_type": 784 - }, - { - "contents": "BA87E5F9338B888B0ADCE8C80BFFE11D2467303431", - "de_type": 902 - } - ], - "encoded_section": "5D911000D22DBB4DD6D440F26183BD13D0C3DF6A9004AA523D21ABBF464C0DD1166437AF2EE5159310A4E2C500A84A7824DA48C2DB85C9BC79B60DA83EE61EDFBA617008A7340431E5B7ECB19E7F140D6F0D7E22589A51AAE13A00780820", - "identity_type": "provisioned", - "key_seed": "1E2D99F50E548FC49590D5E6C066B4DC955EF40DDEE79167EC359E551048E1D1", - "metadata_key": "83D500F6D6106BC3C2B17AE408023E91", - "nonce": "4A9AED02A25AF38FB2E2E2F7", - "section_mic_hmac_key": "B29B84CFF65C3EE4616A502AC61C029C706D6B1EDD39EDF4D76EA5A84453BF5E", - "section_salt": "D22DBB4DD6D440F26183BD13D0C3DF6A" - }, - { - "adv_header_byte": "20", - "aes_key": "5BA9C6F943DAF529109F4B100F49D597", - "data_elements": [], - "encoded_section": "35911000C739C6227A353DD9B0EB277131E35DCF900469ED27AFB7C387B5475E150CD81AEC4884892FD73C27B796E7685D75C10A7F71", - "identity_type": "provisioned", - "key_seed": "1344FE8EFB2E14874FEB0571343BBA222C0FD904204BBA55ED94F0CD28C26FB7", - "metadata_key": "DB1BAE09B154172E09141BFFE4CF561D", - "nonce": "108AA9D4432E50BCDECCBD6C", - "section_mic_hmac_key": "2E20757E70673D996C6D58E403A0F87CDE24F7EE3038C17FE07D435B44093CD5", - "section_salt": "C739C6227A353DD9B0EB277131E35DCF" - }, - { - "adv_header_byte": "20", - "aes_key": "39CD401AE8F611D1651E0FDD59BA8F45", - "data_elements": [ - { - "contents": "F4658B8BCCCF49B7AB79", - "de_type": 564 - }, - { - "contents": "C9F2A6B90E08CC", - "de_type": 988 - }, - { - "contents": "820BE5C34A2CC3E9", - "de_type": 870 - }, - { - "contents": "0F02CD73", - "de_type": 573 - } - ], - "encoded_section": "5E911000E6CBCB218624EE2DC2DBABAB38F837769002F43D65267B214BF792B14655201C57B346BF233AEA5FD07FC5163FE7D1659F6A8DB901B503D26320F94D3B25EC2647F294BAD0748EEE05FE24F42CFA240062F74715FAF8CB6873C017", - "identity_type": "trusted", - "key_seed": "D72CDA23016D822CFE1E5294916DC83CF98EC2ADAE9121F80803386DC5CF6E78", - "metadata_key": "47001AE1B7E542147BF57D1C62F22F9E", - "nonce": "B677F8EEF05E5C4FD69BC645", - "section_mic_hmac_key": "CD8F4F64EB964FF7E0EFE036347DD0007A1A763B3001F02361CCC3A680C368FF", - "section_salt": "E6CBCB218624EE2DC2DBABAB38F83776" - }, - { - "adv_header_byte": "20", - "aes_key": "194ED59DCF4144A697CD1AD63E33A3B4", - "data_elements": [ - { - "contents": "D5156EF7CAD1096B1EBE82E0", - "de_type": 777 - } - ], - "encoded_section": "44911000032224758D14BA41AF92F6D88A501E2C9002C7D754757898C9E34AA838CDFBAF155B30084E02BE29B58C33ACC954F941842FC053B0ADD4CA9F3D3618EDBA2CDA81", - "identity_type": "trusted", - "key_seed": "F77600BA15BA4C8B396C8A0C3B8ABECF2B064A045E583BECD39116C572E7AD12", - "metadata_key": "DB7F42852277D6552C91815416FCBF72", - "nonce": "5A2D8E75D0B7634F06D7325A", - "section_mic_hmac_key": "862D13102D1431D175E2E8B6ED0D30D99C6E43EFED3FCA6D14CFD8AEA3BBE15B", - "section_salt": "032224758D14BA41AF92F6D88A501E2C" - }, - { - "adv_header_byte": "20", - "aes_key": "3337A6A8FC085CDCD20C3F46E78E7AB5", - "data_elements": [ - { - "contents": "70D83068132E37C88B72A4EE79D173537E8F", - "de_type": 277 - } - ], - "encoded_section": "4A91100013D9056CD070347F927B0F615DDFEC549004C7894D8A1B5608C1EC182CC0AB86375EEBFE92E0A4EF6878AAFBCB637738E21F4EA1C9F76D65EB4AE29BC86CE43C9F49859C66F2FB", - "identity_type": "provisioned", - "key_seed": "1507CD75F60429CB9E63C4D4A09FEAC92E772223D9E95838E8784AE1969F3E7A", - "metadata_key": "481E466127EF90D5C53596E8552EC52E", - "nonce": "F7A694ED8C95C9D7A755D82B", - "section_mic_hmac_key": "F7355B49456F6C57FE860ACCE4A711214D71D5F08B574E5BA37E165B52000A36", - "section_salt": "13D9056CD070347F927B0F615DDFEC54" - }, - { - "adv_header_byte": "20", - "aes_key": "FBB1328618CCD896CC70AF937CAE8281", - "data_elements": [ - { - "contents": "467333809F3B", - "de_type": 952 - }, - { - "contents": "50CE12F4FF7B16B5643EF1C66368DF27DEDF3CEC9B24A3", - "de_type": 300 - }, - { - "contents": "08443858DD0A", - "de_type": 124 - }, - { - "contents": "E873C2B86B0C5A28624DBBFDE0AE3D22D03EABBF5BA71EAD", - "de_type": 448 - }, - { - "contents": "F1447D2F9281DBEE34476C48B22351E8F27CB782A10A29FA69E5ADCB3EBE", - "de_type": 399 - } - ], - "encoded_section": "9C911000E33DCEF3193A00CA24590E41CB1607C79004439EFC4200D70EB58A7579DEBD80F04B5E8002A076C37A1D6510BA493BBD60569363F1FC3FC5A379DFEF1BDE620330DA1C8D06AB062EB96C92762FE17DD96776B35D13CA41488C1C83F2FFE0D0EF5262B632D856D10CB666762BA5CA742A0E9E95C9931779E319C7854ABE32BE0480D1FA754E1EEBEB1521C148FBF4A70F3185091CB04D57884A", - "identity_type": "provisioned", - "key_seed": "D30C0A924112C23C73BAC89EC03E7F9EB81E26916553AB6556C1240C20EC37B5", - "metadata_key": "308A7C574957C93A9B3E6CEA175AB263", - "nonce": "5D0946C2808A4C895626EF0B", - "section_mic_hmac_key": "8421457116D650DB88EB790AFB90AD99C53EFE2F875528CA25ADAA615F35D9CE", - "section_salt": "E33DCEF3193A00CA24590E41CB1607C7" - }, - { - "adv_header_byte": "20", - "aes_key": "E03DF6ABB87D6F554B5BEC78A7E8B0FF", - "data_elements": [ - { - "contents": "B94A3080F25FE185C6C36E9A21405519666684E0847BF36DD115A926", - "de_type": 503 - }, - { - "contents": "", - "de_type": 415 - } - ], - "encoded_section": "5791100094339CFAA454A5D2E977F38C35E2844D9002E15B4F8862B4A3E4D5FCDDEC6FC36567A1E9A6EC6E2CAAC28CC1C72CC81CB4E190AD8C8C1997EDA2A8391662DC44D4D5B818959ACC574FA1CF7E99645C4DF138B587", - "identity_type": "trusted", - "key_seed": "6B1BDAC7E669C8EF0847707AC2365C0D3864B31D6F13C088D4630CAE016B520F", - "metadata_key": "A50CC2AEFD3369D7D1DA0F0D0E537F19", - "nonce": "0C4819136C0E397ABDD9E354", - "section_mic_hmac_key": "A1FC278429196727FCF080260972AC6BAE2670C7383C2E297D1721428168F8C8", - "section_salt": "94339CFAA454A5D2E977F38C35E2844D" - }, - { - "adv_header_byte": "20", - "aes_key": "D79C9AC03BE4012DC980193BFD6B9844", - "data_elements": [], - "encoded_section": "35911000711C9EC86B8A068AF07B7FE5C85CC9D39004D54FC742603A383E4F153DBB7462EA99ACDCA8E5B667784D8DDB99FE360DABB7", - "identity_type": "provisioned", - "key_seed": "6FC2E3B1B4E9D1A97ADE86D36D78F377C5AF881DE70D981C8553DB86D830F617", - "metadata_key": "FFC3763940BF40D4C90C1C9F1A108195", - "nonce": "5FB63D89B5C5D0A2908B0A62", - "section_mic_hmac_key": "3F353E77278CAC09E16D0F86B6723510700210D5C8A73E6EEF04921FDDE689F1", - "section_salt": "711C9EC86B8A068AF07B7FE5C85CC9D3" - }, - { - "adv_header_byte": "20", - "aes_key": "CDD28EF3B99341DA9DE1C30C254E4430", - "data_elements": [ - { - "contents": "99CE21E4964A6A7C14E6BF387369", - "de_type": 361 - } - ], - "encoded_section": "46911000E9FF177F159C1A081403717389F200EA9004505BB69C948A0A4849FEA66E702DB7500BC961E0151EAD701AA1BA69C29A1E2B363678656DB7E72D4A98AA28A8894CE84B", - "identity_type": "provisioned", - "key_seed": "A2A3EBFA3847569FDC2713784A56CD71A1DEAABE14190EC0B86AF832EEBBDD59", - "metadata_key": "4432862698BC0A055C41E6219F86C655", - "nonce": "64C1217301A32C5B82B94358", - "section_mic_hmac_key": "C78D782F47CBEC0D0F0470DEC491B8808A6C08E71F5C325E0B359551AE38ACA4", - "section_salt": "E9FF177F159C1A081403717389F200EA" - }, - { - "adv_header_byte": "20", - "aes_key": "F2912200A19661C7B3256F2ED8D635E1", - "data_elements": [ - { - "contents": "7321", - "de_type": 467 - }, - { - "contents": "", - "de_type": 743 - }, - { - "contents": "B58EA8527B77EB7DBF5CF9D10748D743DF6E8F37D8", - "de_type": 592 - } - ], - "encoded_section": "5591100029FDA91C6673EE9F5E81041BE492146890026FF0F473F33B7DE9BFA2EA578382EBCBE4227D5570F2365433A6A4751FD10BA87D17552C9315E4ECA5A45D4EA4F20AC118D0CF61A0E0E49E90C9658FF4D1CC6E", - "identity_type": "trusted", - "key_seed": "FD7967CD290B0ACCA1FB012C6B17FADB54CC062A92E4E3F095B6221265606BC3", - "metadata_key": "7485DC8BD4A36F721112C2947751F068", - "nonce": "CF3A08D31D6DB3F85ABFAEFC", - "section_mic_hmac_key": "DE0AB90DC2E5437C201A96A529552965E9113AE01E76E225E906DB2C854C4F74", - "section_salt": "29FDA91C6673EE9F5E81041BE4921468" - }, - { - "adv_header_byte": "20", - "aes_key": "425A003859115F90D385DED38FC3138A", - "data_elements": [ - { - "contents": "FF1E4283ACD7", - "de_type": 592 - }, - { - "contents": "FBE130FC8F63BD7012", - "de_type": 224 - }, - { - "contents": "7DEDF0BFF3CAAB7C6EEB72A4F7B906AC50A92F6E27F0C0BE5DA402D6E1", - "de_type": 740 - }, - { - "contents": "B3929F152C596C0BEF4233703F00B6621C1FF3A358F3C86DCFB16B72", - "de_type": 312 - }, - { - "contents": "0F5043C11D1C467CCDCB83DCE0BE43AC1D94DD5611", - "de_type": 891 - } - ], - "encoded_section": "A1911000D3F3AF795C519468EFC23F73081ADE8E9001D17E0B80D5304A3B3078ABD224B53EEFF7BC4D82C69097FE3731085ADE750593E3267702827CB9CD176EE205CCE43458E2AED220AABE1587FF7FEEFA571B629E2A205D207044EA651809B9F5C9102C35E0368A0C22CEA27DAF899A987DD40352EDA04C8DDC7ABB3B6F279C7779162B472543393F37A9EE4A9A6F1E6ED3EC8E46551715F1F254A13E0604C71E", - "identity_type": "private", - "key_seed": "CBD5BDDC7DF1CF4DE8C67B8C5D8B3936E4370BD2FB8674BDD032DAB651935098", - "metadata_key": "85F9B7DC74148374E28EE18DEB067DDC", - "nonce": "64822DF95082DD9FAC3ABF49", - "section_mic_hmac_key": "DCE1733FCC2792C2FC5E717B60BF387A153B202A6FF51896D67849A33D700BCD", - "section_salt": "D3F3AF795C519468EFC23F73081ADE8E" - }, - { - "adv_header_byte": "20", - "aes_key": "7B1388703BC7E6A02BC3FD5ADA646469", - "data_elements": [ - { - "contents": "7D62FA053E4F6358FFE38CC63265B5C631", - "de_type": 618 - } - ], - "encoded_section": "499110000FB390BC9AC7F8533F693FC4F1C9BD6A9004BF6D2926E7409C8B991DDF484AF4F056C15513C85442EF6D8CA694BDCCDA70B5ED790BFBF4F026113C0E71CFDE64EAB674438D7A", - "identity_type": "provisioned", - "key_seed": "2B56B30BAF8A4D98B8D2D6DBBA920C7E58CC2A308BCBEBC2444E695CDB84DB9D", - "metadata_key": "F9B398674610A9887928F01BFF47348C", - "nonce": "CA88F80E008C85191F0368E2", - "section_mic_hmac_key": "61032327C90BA52D7AE489911943770F4ADC0CBFF70B3C1FCC6C8CCF684D11DE", - "section_salt": "0FB390BC9AC7F8533F693FC4F1C9BD6A" - }, - { - "adv_header_byte": "20", - "aes_key": "C131B7DDCCBF6B9D6697A73183BB9C2D", - "data_elements": [], - "encoded_section": "35911000D6A73EDFDB9C58847962A374CD39EF8E9004564B9DA3B33DE90A04DB8E09C9F74E39B3974D254418BD31BEDAF2079776203B", - "identity_type": "provisioned", - "key_seed": "619CDE7F5C7F48C2A728740F73ED8BED80DBC75A8F80A210B7787A3CA7D99894", - "metadata_key": "894C9EB0A0CD63439D7D38D98271886C", - "nonce": "988D2E9390677C9D60D253C7", - "section_mic_hmac_key": "B9ECF2780619E5BB483F7E67D47D5F6C453260B05B1C6C8B9DE3A1AA200E859E", - "section_salt": "D6A73EDFDB9C58847962A374CD39EF8E" - }, - { - "adv_header_byte": "20", - "aes_key": "471C247B67E71991EEA742A60395E761", - "data_elements": [], - "encoded_section": "35911000AF15F574B747192E9BD4F216FA1B4B7790046EBE5844F9C2B310D203E1F7B096319C81C5F10A0173AA6130BBFFDE2C335BA2", - "identity_type": "provisioned", - "key_seed": "AC53B58E3C5655CFC99E96EDA60B6356B91878707EBBB72C58B40372067F2654", - "metadata_key": "B3C7283A417F10365A58239881EA3357", - "nonce": "36F08B54F7A71C96317A1379", - "section_mic_hmac_key": "C873EDA6670390B6576A70192A1CC51663DC71878502344B4E89570B4DEB8CCB", - "section_salt": "AF15F574B747192E9BD4F216FA1B4B77" - }, - { - "adv_header_byte": "20", - "aes_key": "FE9F6FB58671E09A1A982B395153F5AA", - "data_elements": [ - { - "contents": "3EF87149ABACBBE77A658C12AF57C5CC23549860", - "de_type": 886 - }, - { - "contents": "2FA53563", - "de_type": 266 - }, - { - "contents": "07", - "de_type": 504 - }, - { - "contents": "D174D239EA526214B9F3DFA561C2E67AEB39CB5E8E45006EF7", - "de_type": 727 - } - ], - "encoded_section": "73911000996E2F8D9CA965F32EB4884BFF25EB659002555A82FC0FCC2977E3F47AE4C3ED20652D644EF87BA79F9C7A4D0CEFFF756F6F3EA21275055C45685B915A6CF3500FEB68C62D6DB778D6037719D08E1CE1A47A60BFA574B92458EA9853CA12C6085EDC5B3357767D033BB8BD858C6C45F4", - "identity_type": "trusted", - "key_seed": "797A0E23E450BD746F50A900291EDF12A427207E9345F1ECA7F247754D4E3778", - "metadata_key": "EE52E516F455BF41B9FE45B525300D80", - "nonce": "8032538D846F75783A371130", - "section_mic_hmac_key": "7B1519118268CFD05BE2529648964A31267DE90B31858A541E3B6FA5B5A5BA48", - "section_salt": "996E2F8D9CA965F32EB4884BFF25EB65" - }, - { - "adv_header_byte": "20", - "aes_key": "259CA266C07D24489E2320751FFACA50", - "data_elements": [ - { - "contents": "1293957F338220C0DFCF99BB988D4B10A2", - "de_type": 588 - }, - { - "contents": "A66E4E117DE27225", - "de_type": 527 - }, - { - "contents": "A371A89597B5908CF70EB5CD70", - "de_type": 348 - }, - { - "contents": "EF8C4B", - "de_type": 893 - } - ], - "encoded_section": "6A911000CE373177E0843767D3CBDE3EE36AF17190041C77A0D1B5A6D84E23CEA79D55760F47327519B09C00EF56BA591D952D09BF7649316ABEAA1DB8CBBA6C60CB9800B14CAA592DC6BE015529375E516D04DB3364041E1CD3C4545F053AE220D2AC5D9A1D8F15A18A5C", - "identity_type": "provisioned", - "key_seed": "0C8BB4BAD43C47257EFE360BD5D5DBE4896E84694141ED2BFEC0489578B217EC", - "metadata_key": "0F57379CD24569CF8D875802667F8018", - "nonce": "2537E78DBA5A7038AD729338", - "section_mic_hmac_key": "FC12ECFFC1AA17039E7B4D5671BD50D23427170DE99771C2560D50630AAB4FDC", - "section_salt": "CE373177E0843767D3CBDE3EE36AF171" - }, - { - "adv_header_byte": "20", - "aes_key": "75678439AC49152DF67381CC8EE0C97D", - "data_elements": [ - { - "contents": "AAF565A6056E72F5701175", - "de_type": 900 - }, - { - "contents": "", - "de_type": 882 - }, - { - "contents": "1BE514ACA5DB37", - "de_type": 958 - }, - { - "contents": "4E37988B6C6BEA4DB361B0ABA2BB437B4AD2A36629E927A798C952DD", - "de_type": 994 - }, - { - "contents": "7A7051FB81E50D6E053F5485690060BB125BF0B564C25E8141F18A96", - "de_type": 502 - } - ], - "encoded_section": "8E9110008CF745CF3EF5643BF08137D12572917690017A062343BD2CA81B100320E63F160D60C0E4FA222E7E8D2DDEEF54E8DB3E6F1FB8ED544B20CCC68B7325C41E13169FF9243D361927D8B8D70CB9BAD2BF8D144A7E7181AD04B286370859944B00B285A07237C9B7C06ECA02F133C1ADB18676DB418CB0F625548CEE8D1EC557723967A2DBE6B6FDE4266E810D", - "identity_type": "private", - "key_seed": "B2289A540886CA52A77D25F5130E9772E28FCE89F62ECC13606D63DCEE99DA3F", - "metadata_key": "982AE1A57B20C2386179D149B6EF266F", - "nonce": "80CD1289986D617F60412E98", - "section_mic_hmac_key": "7568EA434871461F5D6FC2DD811AFD04A037DDA922D703E0C62B59BE3FD8463B", - "section_salt": "8CF745CF3EF5643BF08137D125729176" - }, - { - "adv_header_byte": "20", - "aes_key": "7BB7CE9DD41A841A3D5A7EFD4C320177", - "data_elements": [ - { - "contents": "AFD0D457BF0EA8EB58FB", - "de_type": 663 - }, - { - "contents": "2E252A7580FA1B62063666B69F3C6332E4B8F9707C7A21E9E02950D9C5", - "de_type": 817 - }, - { - "contents": "B60A909ED57A8DE3A7860923B92A7D5F6A8D", - "de_type": 800 - }, - { - "contents": "B6C8C14C3304DA", - "de_type": 874 - }, - { - "contents": "44359C8173B6FB9A92391A0EAE5C6CED3795595BF808E685FEA3800C", - "de_type": 41 - } - ], - "encoded_section": "9F9110007C40D5971CAF5E56EA8BF03ACE6BD22D90029D30A51708C5EF060F6B2302BBAFF4C86DD795B8E6C90593DF259C7456F78C3C538BB0F15EDF17939A6C167B07648A62BBEDC503DBAE8861E36C6D465288149E9E99BC0514AE21D81EE7A68420BED4EC65D36A625CAB083EF8AA67EBBEAE047778D2B1A6DBF17FF25BC013B70582694E68E21E45C2537CE508A82751F5079DA2D24255E6800D7B48241B", - "identity_type": "trusted", - "key_seed": "ED15F635173F72E83E0FECAE6051EE847DC187452B21CD45FAB6695D6B46FB6A", - "metadata_key": "FA3B46AB691AAA00B09C9CD962E3811C", - "nonce": "40AB25BE3D15124FDD3852C2", - "section_mic_hmac_key": "EA130B96787E966323391209C412448E67E2554BFC79E1D0A4C1D8F28D29840C", - "section_salt": "7C40D5971CAF5E56EA8BF03ACE6BD22D" - }, - { - "adv_header_byte": "20", - "aes_key": "09E7B0FA69B5C2148852706F8C5F82BD", - "data_elements": [ - { - "contents": "8C43E3E02909D0E210F56F35F3A53ABDB0", - "de_type": 153 - }, - { - "contents": "45", - "de_type": 747 - }, - { - "contents": "EABB820A273B4051E4", - "de_type": 653 - }, - { - "contents": "", - "de_type": 828 - }, - { - "contents": "640DA947E4BA04CC0C40BE9FA8DA6819E90ADFAB03675A24BC2D66E541", - "de_type": 780 - } - ], - "encoded_section": "7C91100049432641BB8252194672F33CAECB191190047289517226E7FBBDE5818FD68CEAE9209FF8BAA41136E4807358253C75094411B689D301DC04E3516A85D40B21DF0700D7B92EC91D1EEA36287C7705A61105847DD7D8A428E634D74A99BE9AD6EAA73D38FE8F69CE611C48AB50D989C8E64F6E8E01A44AD1A5B2", - "identity_type": "provisioned", - "key_seed": "B169199CF07A1D54ED407BF64823FF86996412B093B8484B37834D8924EF93D4", - "metadata_key": "9E2A47BDDF6F1B9BEA356760D0F3E69C", - "nonce": "1BFD42F51287EB2A9F5E1F4A", - "section_mic_hmac_key": "3BC6B7E8D9F2574AFDB2475C7446292E50BD425D7C29210ACBB02926A8BF3446", - "section_salt": "49432641BB8252194672F33CAECB1911" - }, - { - "adv_header_byte": "20", - "aes_key": "3895442EB8CDC0F81A3C413255B87845", - "data_elements": [ - { - "contents": "8A78F02365C12DF7959D96CD0DC8D50C000230D7500F2773BF92", - "de_type": 791 - }, - { - "contents": "6494FA1960D6F8", - "de_type": 709 - }, - { - "contents": "DF5B46AF34309403DE697850F22EB80BEB", - "de_type": 10 - }, - { - "contents": "5BB5A41FF36679", - "de_type": 284 - } - ], - "encoded_section": "79911000543133A572BF9818330781F72566EBA39001945FCDA195E5DD57E890340E1145DDB3E7F29F61570FFC84C816A65BECF670144691E6DEED393F745D1C2FCA8F81A02EB783E970DFF3182D3A0DA22DC6046EFA6AA8311E1B7A9B9B3397B1C7F2DA32F5AF4A59698565FEB006903A3A2BB2AA774E65DDA3", - "identity_type": "private", - "key_seed": "41A397419E6A7A9BAC80625800C7C5CFC5A9E38D334423670A10C95B46385944", - "metadata_key": "6DF6268ABB94ED2B7572647828350E37", - "nonce": "3FFCA5B7F335F4080095078A", - "section_mic_hmac_key": "8E01172131A0E1AF5B2E800FBB4F6B941561F6A25326CCE3FF8549C87F059B75", - "section_salt": "543133A572BF9818330781F72566EBA3" - }, - { - "adv_header_byte": "20", - "aes_key": "FE335C4919EB054F5D03A0F3659BB5ED", - "data_elements": [], - "encoded_section": "35911000CF8C1FF97CECF7F829F6C8A71E77CD779004792DD541DC78082D871E1191261E74A3B8E20A809244EC191525C631BB404865", - "identity_type": "provisioned", - "key_seed": "354C47FE5F08043C0739F02C7C491A5CDC2ADEEABE5C95CA26EF56D3301F32F0", - "metadata_key": "0CBB7E1212820A68D7DA2C386E9CA368", - "nonce": "D0CF770C2DF7104179F8FEA3", - "section_mic_hmac_key": "D94E767398418969D4D7F94690A8BCBE3E5D7F85990B958A83FF465E723CA19B", - "section_salt": "CF8C1FF97CECF7F829F6C8A71E77CD77" - }, - { - "adv_header_byte": "20", - "aes_key": "ACD71592FCB1FD6C6D8ED46C23769315", - "data_elements": [ - { - "contents": "C8A12CCC17EE72A7AB87A19A", - "de_type": 38 - }, - { - "contents": "2A0E63613F23C6B46B0C7FA2F22112381E62F5B1E9", - "de_type": 129 - }, - { - "contents": "80F038E4063FBDCD0612FE767119359E", - "de_type": 564 - }, - { - "contents": "4DA8FAC9B8994DB6", - "de_type": 3 - } - ], - "encoded_section": "789110000F3ABCDAB5986222DDFCBBB8FF38566C900428609F59EC9E471AA93544E7103F645AC96E4FAFC86CDD5CDA58B682D3FFFA015B6578E6C2E1C21AA406B7175401D3FCE1ABBE909A2A50C0804D4E1A8CAE5E27B1BED0823246EA34539ADC01915175F58B47E44680672B72EF54451DD632977507326C", - "identity_type": "provisioned", - "key_seed": "23DFBD6B52C3B59B254DB98D406E8479C25020C1DFA630A8BD2C89F88080C615", - "metadata_key": "379389FFDDE6252B5130D231D63472DD", - "nonce": "15F7BCC7074470D3F1CFB56D", - "section_mic_hmac_key": "BBD2B93E7B2477438E34C1205D0BCE0B365A7BC302EDB5CF0F82B6894603E24D", - "section_salt": "0F3ABCDAB5986222DDFCBBB8FF38566C" - }, - { - "adv_header_byte": "20", - "aes_key": "BF15896C0DB200DAE1115AC614084DA2", - "data_elements": [ - { - "contents": "B874CE053E51E004F52641A7CFB2D3B0FD74B7DBE178776A671A0DAE2F", - "de_type": 302 - }, - { - "contents": "913E81800F04456267ABA9E4782859A4E1C7F9BA7E9F", - "de_type": 115 - }, - { - "contents": "803EF3051156701AB4EDAEF5FCB355594348E96537E5EC0571BE99", - "de_type": 353 - }, - { - "contents": "CE22", - "de_type": 749 - }, - { - "contents": "8BF83F936CA560AF25B8E0FD2C", - "de_type": 140 - } - ], - "encoded_section": "A09110000909CE4451ADA9FEAE94AFC32F74DA8C9002500BEFA6439AF0E094408096D11836FF233FD696C45B67FC5FE377CA37A7156D30C7747C04731ED487D679E79747AEAB7B9264C1F02FF4B3B56A6282FF1BA99927C50B6CB9A5AD8300C58F0DA8D189F7B891E3165A3951B9587FCEAD411774E3C191ED51D02878659572425B45D0098395AC66421C05B5B7984A66B82115AB609678A5B2E8B109BB1DE8AE", - "identity_type": "trusted", - "key_seed": "D32BF06FA8E93B413768C8F0CD5422EC87FD4F07A83471240BA220E36153FA02", - "metadata_key": "1FE225A34E0798FF526E8B55F10AD9AC", - "nonce": "B54225F9D30F237B635A51E4", - "section_mic_hmac_key": "CE683F20EFFEBF4F062DA3EEDB52DDE50B32C8D63BF2B8A5551EDDD354940500", - "section_salt": "0909CE4451ADA9FEAE94AFC32F74DA8C" - }, - { - "adv_header_byte": "20", - "aes_key": "5C0FF3E5206B0B714A43B06D56DA4CD8", - "data_elements": [ - { - "contents": "B83154F8BF3A58B9F7F622486850E19C9798FF7B0D2B57DF1ADB", - "de_type": 604 - }, - { - "contents": "2855D0AD4AA6C16ABB392AA9EFD8A0973235E86129F8CD652F1F", - "de_type": 362 - }, - { - "contents": "8744051612F79A9F05D48FEEF1F276B6039B4EA57B", - "de_type": 639 - } - ], - "encoded_section": "87911000DB30A3E8AB8EB0FFE1A3C1C32107E97F900229702D3456ED474EB3634E1123F78A5EE68795E469986D32E140F7768372A49544565B77EDC858130D8F31885D21142238E6160BFBC4AA1E2C16617029B098225727DBE761B39D8C4F3A9B81DD79320B786B8A73AB12495BDCA873416489EFA679DBCF4D890CB24953E193DC729A7FB13CD7", - "identity_type": "trusted", - "key_seed": "CBD84DE224729EC23993EC958BA5EC191C55984C7565A37C202C66BC2F496DC5", - "metadata_key": "E2C1CC17E5DA3035D3A4A9D67B696A8F", - "nonce": "1769E6807F6DD41EED99365E", - "section_mic_hmac_key": "3B760F5F10A764D965E928C2EC75BF3C185BC1E60F1BC25E3A4F2A23B08275C9", - "section_salt": "DB30A3E8AB8EB0FFE1A3C1C32107E97F" - }, - { - "adv_header_byte": "20", - "aes_key": "EF4525C9E148E35CE5B6B1ED3EC7F397", - "data_elements": [], - "encoded_section": "35911000F37AF80B78106073DEE5B3E89CBE817690015242E1B8F8D5B0AD1A98BB81C0B7AA6E2F08129AA0AC99057C4EF93D009FACBD", - "identity_type": "private", - "key_seed": "45E271D048743BAF708F32EAC2E0C37B0AD50DC468268F45FA5A00F273710BC8", - "metadata_key": "D5BB4FEA17C7E817338B14C4D01F95AA", - "nonce": "9EB99045CCBB3943C3C85689", - "section_mic_hmac_key": "94142F9B2D08B819B2681AA5A8532AA239FA5D248DE1400308218E1171A19B2E", - "section_salt": "F37AF80B78106073DEE5B3E89CBE8176" - }, - { - "adv_header_byte": "20", - "aes_key": "D7B12DF79375EAD42C400EC4B32C845F", - "data_elements": [ - { - "contents": "5EC3", - "de_type": 27 - }, - { - "contents": "9E9931D907110614B32CD6406AD1F2EB87A10F09B7E8E787112EED", - "de_type": 473 - }, - { - "contents": "D832A59D", - "de_type": 739 - }, - { - "contents": "F9A4AB6E8C79AA9949", - "de_type": 326 - }, - { - "contents": "DA3460FC544F1F95", - "de_type": 983 - } - ], - "encoded_section": "759110009631F8139C4DBED9E68452694DDFC8839004ECDED2D0BE3DF39682EB8C2218A08B11479557857995B61401E0F13ACAAD078B464F1BC371BF9374A4AC12E24E92258EB2020E02A85BBB90568AB3BF976B36BECEC7BA4D0925816AD13747288FA4FF6F5533C22E342606A7B9929FA0A5672FAB", - "identity_type": "provisioned", - "key_seed": "869972ED54E5B68EF1C466213667435B7C08EBDDFB74F685ED7E16CADB6BD315", - "metadata_key": "4B943DF47FA8A1A5ED1983F6BA680BF1", - "nonce": "0A885C98D19D59923D1D4CE8", - "section_mic_hmac_key": "0FF1627C891D82AD29699A9382972D0D134EC708C71ABBB25F117C50E7564E7A", - "section_salt": "9631F8139C4DBED9E68452694DDFC883" - }, - { - "adv_header_byte": "20", - "aes_key": "D99D1918B0ECB9895C5079AC3708F8DB", - "data_elements": [ - { - "contents": "9504B53F3858406A21CDB1A8E6E4726EE54D26EF868A1CD0FB3FB6", - "de_type": 354 - }, - { - "contents": "", - "de_type": 219 - }, - { - "contents": "E68CCEB0AEEAD509B8D936D690940E628CB3446E7A5AD4", - "de_type": 570 - }, - { - "contents": "27C89F3446D81FA865168C6942", - "de_type": 663 - }, - { - "contents": "A7B1EAF81C107EE58AC4433F9B2F9194A1C5B3B31F7DBD775E8C", - "de_type": 854 - } - ], - "encoded_section": "9D9110007E27BC504F56BB2720C62A72226B8C369004EF6CDC81805C1A1B8C3689B047217487EF72A690D9EE8B7DB36DE15EBAF6746CD77D0E9C979344B10045AA56EFEC9ACE8DCB27C444163CEFE58CD7DB8F33F3BFB3F34483F7EDA5D0BDF0DFDCD63AD61AC00E548B445F480EE3F2B5F7CBC8646CB6C916CEBB660725C6735F7105F9FBFA765E51EE242D53E97F79F4FD2151590529DE523296437B2B", - "identity_type": "provisioned", - "key_seed": "C50E2225963721E5B6EFCE5B1A228B14BDD2BA34AA67E7225550B081BAD88726", - "metadata_key": "062D3B665FE311167539CBC5BEAB9BFE", - "nonce": "E35AE35D209210B3880DAAA4", - "section_mic_hmac_key": "80C63B2ACF7CF9FAC9852D0208BD4797B5DCDEF5A3F4BA561D07FD2ABEED9F03", - "section_salt": "7E27BC504F56BB2720C62A72226B8C36" - }, - { - "adv_header_byte": "20", - "aes_key": "905119285260089FF9BE8FF6CC825E02", - "data_elements": [ - { - "contents": "C7773F175A4EE4", - "de_type": 167 - } - ], - "encoded_section": "3F9110002F823378B9F59BBDE54978A162E849E09001CA8F84780BF04A3EA8FBE518141707B75121CDAFB8F0E4A24D354D5775AD46CD6E698AD77AC066B5250F", - "identity_type": "private", - "key_seed": "4D8C6CD25657A64D6A4FC29AA77B921362224AA73F33A03B48A547BAE062F80F", - "metadata_key": "0E77A2EF879199FCDB210192BA8F61BD", - "nonce": "71FCB2AE5A7E75EA035E4C2F", - "section_mic_hmac_key": "4C314CD5B4BA1DA13BA002B6F8B5B23B83E52A3151E8D3188B18A9116D393FB5", - "section_salt": "2F823378B9F59BBDE54978A162E849E0" - }, - { - "adv_header_byte": "20", - "aes_key": "58242E8A9A5B025E720AA40BA1CB864D", - "data_elements": [ - { - "contents": "786DF190FA", - "de_type": 989 - }, - { - "contents": "C35CCE593DFC7F1B67D9FDB6DEB00A", - "de_type": 8 - }, - { - "contents": "CD5807FFDB0B16362997F91B45C3F1", - "de_type": 736 - }, - { - "contents": "AE7B1B9F94", - "de_type": 485 - } - ], - "encoded_section": "6891100064EDA38990FF5640000A6F909B9B4C339004B2D2CAA61055C3A3B5B633A6864D112D20D55DD235B254BD1B4DDE1ED246B422D549F6ED9EBA4E61B144AE199F41786257AFABFF2D09F5ED1D551AA90897424C7DE78D9F4211352DFC23D15FA49BAF2AA3160C", - "identity_type": "provisioned", - "key_seed": "930ABBE8D4AA0392A66E624A958254C607E161BDB8F63C4DB39E049C200AA63B", - "metadata_key": "06190C656B704517A79EBE4A713C90D1", - "nonce": "08746932375AFD8D733B8CCF", - "section_mic_hmac_key": "E9018DBA2F5D458EBF7F765F5E0A291DC789BF054BDD7F21ABB08F3C9CE0C068", - "section_salt": "64EDA38990FF5640000A6F909B9B4C33" - }, - { - "adv_header_byte": "20", - "aes_key": "2E74FA5A2A52433667B756AB26FCD187", - "data_elements": [ - { - "contents": "A60BC355C90F28BC4939E07D1CE8FDA9F3BFBC190219B42A0396EBA4F4C0", - "de_type": 59 - }, - { - "contents": "5D789F74C3EDE4BC72D2E79DE9AAF8", - "de_type": 990 - } - ], - "encoded_section": "6791100074C764F6E930524EF16015CE7D9861A090016D3B7274B511B5F2C9F5A18052F777C5F86FA997CE3BC22C9C6C9A5CA085DBE6488B2A78C6A73EC270656AEACCB923F608AE77568EA51827AE96FF9E6CE819A78E0A4EB2C5CA3B4970BD181F397E3E98EE7B", - "identity_type": "private", - "key_seed": "2AF41D8404581C2831B893C7DB59D544B64CFB736BFABC81A01C1875066EC279", - "metadata_key": "CAAFC39835637CF21D4B75303E2CC3AA", - "nonce": "22231C84688BAF0FB9538C9F", - "section_mic_hmac_key": "795A1998284D2DFE1A0E29D8118E10D830AFE527DC341E2654B88F2C1EB1B06A", - "section_salt": "74C764F6E930524EF16015CE7D9861A0" - }, - { - "adv_header_byte": "20", - "aes_key": "7B2C7A448A3450294EDC49709E51BA60", - "data_elements": [ - { - "contents": "E1CF16D6B5287453B1", - "de_type": 956 - } - ], - "encoded_section": "4191100052105E2C85C91460D02A73EEF05F82709002CFD75D43FD7EEBFBB78A62325C09B1C96593C0ED6CA278F49AF34804167F948B99611B4C536AE40E3B74243E", - "identity_type": "trusted", - "key_seed": "E685FFAC5E3BAAF679C7991522FB5A6CEC3F100597766673D2746868D929D360", - "metadata_key": "6E6DBC6DD5DC80171A5B0DCD03F1BD90", - "nonce": "5677F857950960AC98F055B4", - "section_mic_hmac_key": "F47EFE70DD21595388F4747DC599502C15BDE2199335DF51DE8F50A3E6858EE0", - "section_salt": "52105E2C85C91460D02A73EEF05F8270" - }, - { - "adv_header_byte": "20", - "aes_key": "640ED142DA551CC82073E01140C9F6FF", - "data_elements": [ - { - "contents": "CC848267E64EE36BD16459", - "de_type": 1 - }, - { - "contents": "13C03AE9514CEEA49B840E14C3D8FABB", - "de_type": 287 - } - ], - "encoded_section": "55911000B89F5B7D2D1679457B14537AA5D43AB79001E4AE76D2D7376A024CFAE9AF27D5D51D4409BBE5B1F0ADCE4EA97CA14545F965091703432E7238CD345852880A893E18B154A85EC8F2B0C80B28C20376224BC8", - "identity_type": "private", - "key_seed": "757A5313F590A0A3CB7880514176C98223D8D89B6C366F0A9C3E614A95667FD3", - "metadata_key": "8E48AB97578B936E9DEF574317F5643A", - "nonce": "2F4D288A2F3C29654024DF64", - "section_mic_hmac_key": "87973F076C0DA1706FBFA208CF3680032F72EFD30A1F35DBDD720FEDB5A73FAA", - "section_salt": "B89F5B7D2D1679457B14537AA5D43AB7" - }, - { - "adv_header_byte": "20", - "aes_key": "25B113A142425E28DBF10262674CCB91", - "data_elements": [ - { - "contents": "2DC3DFB78F9FEDA6140EFFF49EA5CDB1587B3B", - "de_type": 38 - } - ], - "encoded_section": "4A911000BD6BA0CD360D3ECEAC02350FFA2287AE90048C31FDA2D808BABB89DEDDC545DEDF43A15DC84FBAF251F8553C3ADA164CD855C3392347333E6ED803F1B35A04CB2DE8491B0AD57C", - "identity_type": "provisioned", - "key_seed": "B94AF2DE34B622260AB6EB5A28897241EF07FD726FF6B46B09AB855B74BCCE21", - "metadata_key": "12188B3AAA6203B3D7B7FFF944B28C03", - "nonce": "27D5AA6EB9343720C99B48A4", - "section_mic_hmac_key": "F36CE020CBD605AB0D5A58EEFC5B13041B3E8EE37FCD23DA8768D05B7E969217", - "section_salt": "BD6BA0CD360D3ECEAC02350FFA2287AE" - }, - { - "adv_header_byte": "20", - "aes_key": "86BEC41ABB2C0615E293D625F5A5CC21", - "data_elements": [ - { - "contents": "796D434C2A64E6542A6E8A182C29A6C0A0D10CFBE5", - "de_type": 697 - }, - { - "contents": "B166F37A451DE048DFFE08768C22CC9E16161DE1FC111BE153E74567A3AF", - "de_type": 786 - }, - { - "contents": "15F72C03BCD436FB515626CC4D45B007465E01F99F141A06C2452D08C031", - "de_type": 75 - } - ], - "encoded_section": "8E911000D67B70722D003E7D47A47A965DDC27EA9002BC3C5974EFF692C78D91B4BC70B183AC34AB08D6774A186DB2EAE6518C429EF6EE80C853B3F36AFF69463401AB265A7841C55974F8307B351ACD0AFC676A7F8E3B6785354E8C8341AC1D159B3449674AB3FC1664DC6A98CBE7B365D5F29CCD0945B37F3DA5B15711A1554A8D20DE4E9C36F89AE8CDC0529F18", - "identity_type": "trusted", - "key_seed": "8D0769C53264F0E56940C303DC296FD0FAC215BB638670FDE74C2D254EC351B6", - "metadata_key": "6E402856AB9B61F6C85EE44427DC3B78", - "nonce": "76315884D2C7B9F90A9E40BF", - "section_mic_hmac_key": "E87538BF29EE50BAE15333A281438C3A5776A0544CC3AB1EF84612ED7D59D40D", - "section_salt": "D67B70722D003E7D47A47A965DDC27EA" - }, - { - "adv_header_byte": "20", - "aes_key": "F22B4181441945D8B70988072189C682", - "data_elements": [], - "encoded_section": "35911000324C90A945FF9A8AECA1AC7F71C9B7FB900106FABFF1B5D76193C4196B7CE59C3AAA8D2FD16CCFA6CF09E8C226BD7604AC56", - "identity_type": "private", - "key_seed": "BD5DE9F03A2FAA422C470AFC4F151615F326CBE3E60828C0ECF68CF1215BB760", - "metadata_key": "60FEAF935A8ADA1C80FECDDB8F4290A8", - "nonce": "74FF9C6FC9B74DBC58D80EEC", - "section_mic_hmac_key": "83F5E26CDD98C91D084CD544BAC0EB6C79F3B79B388575973C75F76C66671427", - "section_salt": "324C90A945FF9A8AECA1AC7F71C9B7FB" - }, - { - "adv_header_byte": "20", - "aes_key": "48543F7CDFE13F94F1FF50E76088C2AE", - "data_elements": [ - { - "contents": "9AB990FC7EF63FC213AE08BC81C35EEF8AAE8DF403E17839D9F25C30C7CA", - "de_type": 731 - }, - { - "contents": "2D33ADC55687CC6D516326D3083A01DF79F7C20347BE2BA49726", - "de_type": 652 - } - ], - "encoded_section": "7391100008FF6026C41A8392B3401F690B0FA3E3900456BD090474095981D8D630D9AC342F4DBB5653D8CC96BB884B960AAF63A142323A4C41B7B287DE61D6724BAE3BD0C9692357BAB8A84265443B452CC632A26228824ED3B278FEA3E89BAB1F849DC2D59B92F7923D886E39B641A0824C5754", - "identity_type": "provisioned", - "key_seed": "80D21E28838910DF3318A81884493AD8B3156E22B9EC94DF8E440963D1E6BB0E", - "metadata_key": "F588CA28D3A30ADB81E4CF0F154FC445", - "nonce": "E3C19711F434B76AB66ED99E", - "section_mic_hmac_key": "5C093723FBC9061053CBE302658A97A8641724524D38B88FA576563153E43944", - "section_salt": "08FF6026C41A8392B3401F690B0FA3E3" - }, - { - "adv_header_byte": "20", - "aes_key": "EC4C02761EBCE92561D9876B86277ABD", - "data_elements": [], - "encoded_section": "35911000812086DBDE127B30D0A49750706EFA7090023EAC44AC52CC19411C1EB8A3B054D3A4DA29BA7AB1F48B2B66D53A0E89BEEA81", - "identity_type": "trusted", - "key_seed": "F905BB1C2C53DE72F94DF4E6D2B06BFB56BE0B64FB9388FA64D0532ECBB2EA91", - "metadata_key": "3FA740734AB4B08F591E7A1678684145", - "nonce": "7DFB4025DEE53AAB242382E4", - "section_mic_hmac_key": "C606528062B1FC77C27EEF4A4C3C2DE18672B5334A4505036F0F7D8E3FED343A", - "section_salt": "812086DBDE127B30D0A49750706EFA70" - }, - { - "adv_header_byte": "20", - "aes_key": "08BF72906B4385228E63E345F18A05C0", - "data_elements": [ - { - "contents": "9EC2961EB5315850F02F", - "de_type": 332 - }, - { - "contents": "75A55F90EBBF", - "de_type": 89 - }, - { - "contents": "5B1B5253D80289F8F01BE72974EEBDC3ED", - "de_type": 204 - } - ], - "encoded_section": "5E9110007EAF5B0AF95F689E81F61A051D316FD49002DB318ECF2B751DB740797728EA96E14ADCE0B2BB27EBFC6D45312379906D6494808D7E9C8BA6242B4A02C4C23223112D77B94131BB9BE739661753C158001AF9CD0EDF73B899AA266F", - "identity_type": "trusted", - "key_seed": "EB8F85BE87A0A9347B3CBECE969B008A57FFEF6E4E8A95F734893EE710B27FE7", - "metadata_key": "825022A58B49C829B9B524E12AF0E160", - "nonce": "B5143876982CFC9AC88966E4", - "section_mic_hmac_key": "F649D8AF765E2E31FB870480932F4952FFCA19301F2FAFCBDB992928268BC8D5", - "section_salt": "7EAF5B0AF95F689E81F61A051D316FD4" - }, - { - "adv_header_byte": "20", - "aes_key": "6FA3188C366D18061138ECE126A97BFA", - "data_elements": [], - "encoded_section": "359110006B869584D8B9A2617A3911586E08679290028283D6FFC57D5D5FC3690502E95413F8BF29DF7EA841527BBBE6DE1C918E5B35", - "identity_type": "trusted", - "key_seed": "4ABD1D1549B74AEECA657499EDEFA7701D724FF427142DFA2ACA1A087455E339", - "metadata_key": "32152EC7E3BD86FB1D19DB1136E934EC", - "nonce": "5F7C76D24DCFE9E61B909C2D", - "section_mic_hmac_key": "89CC3C25CDCE4A6D36EDABF94C225087C455DA885AA113254AB3A71DAB0F27E4", - "section_salt": "6B869584D8B9A2617A3911586E086792" - }, - { - "adv_header_byte": "20", - "aes_key": "46C102A2CFEB44FD44236234AC618374", - "data_elements": [ - { - "contents": "2DAED2D919", - "de_type": 752 - }, - { - "contents": "69642A6B9FA86810", - "de_type": 907 - }, - { - "contents": "C9133E66C06507782EFCA12CFD2255DD2AC3CCFE568E5B", - "de_type": 75 - }, - { - "contents": "11917BC9DB942E", - "de_type": 253 - }, - { - "contents": "B772136AF949D06B3C74EECB6A2877B73140CF7BD459", - "de_type": 741 - } - ], - "encoded_section": "84911000D5B533CD04983822338C7E4679ABF0069004CB79ABFEA568754DF58A73D97993AE327F22F6EA434A49AA5D12110FB08F88A77C3EA795B49DFE542046BE6FF89B46146088D770CA8D4E221D73BEECB978974A7E3A2B29C0FE7002230356778F0AB6BBFC45279E08D93657B5D857EE9915A3343FDFAD5ED96C886E225EE77AABAB71", - "identity_type": "provisioned", - "key_seed": "B45EA904C8AD8040870C0C5996E7D6474109D43A1ED77CFD4EC5A0909ED8537D", - "metadata_key": "F27F824E7A676B87F008B914C697F731", - "nonce": "A9D31F3FC180A643BFD2393B", - "section_mic_hmac_key": "C57B68D19F0C0467792E61C6129CAEFC41C9BC017CFDBF3ECECFE053247C86B4", - "section_salt": "D5B533CD04983822338C7E4679ABF006" - }, - { - "adv_header_byte": "20", - "aes_key": "E76311EA2FA2BD5E23ADDD81EEB7035C", - "data_elements": [ - { - "contents": "F0A613ACBCA74BE6A2B1EBFD40C52E0D66E5AB04", - "de_type": 294 - } - ], - "encoded_section": "4C911000CC0BB7E46499CF0636B26F05408554E39004020E9465725DE7A884C5B175C90015562B2F9B106F9F1AEC608425109ECAC0513AD32D14354CE552859514849D19D6BB59CE2D0EF9A0F9", - "identity_type": "provisioned", - "key_seed": "CC9A75CC75BB1D230A75AE87B6AA6D14E08ECD864C90DFA2C144DA62AA2FDA4F", - "metadata_key": "D1FA24F308946E26486C02AB69CACDFF", - "nonce": "DDA1727B363F44B3A00AC548", - "section_mic_hmac_key": "1FFE447BB7A8331E0AB04BD9E920759CE433094711AAE085EED90F11AAB04DB9", - "section_salt": "CC0BB7E46499CF0636B26F05408554E3" - }, - { - "adv_header_byte": "20", - "aes_key": "E670DF92DE550C7D16A47FF544AEB0A6", - "data_elements": [ - { - "contents": "5297CB087EF89FF30B412ED7FBFE9B", - "de_type": 536 - }, - { - "contents": "C6C348BA415CB959EE2B51B43DAF200076890AD49B044F5F847728", - "de_type": 555 - } - ], - "encoded_section": "65911000FAF0B973AAED0ADA284F65A67CC775A6900191A4765553BDA369F32677FF10F57E0793B4FC72165819EB2E38975021A78E8367C4BC9A94E846F6A04ACCE516355A0A93938147C6908509D1599D7EA96A377B7ECB31F81BA98D8AA01CED9617C410D6", - "identity_type": "private", - "key_seed": "238046E9C80693E551BF4F3E7E563FDB8FC7EF319A4E3405D603DAA10BFA0AF2", - "metadata_key": "BB080335533CFA2002C3FB861236215D", - "nonce": "30A968C64C6D236C78A202D7", - "section_mic_hmac_key": "20309013BDC66CF400D5E221109AB10CF0E742555D8713BBB332648E3897E847", - "section_salt": "FAF0B973AAED0ADA284F65A67CC775A6" - }, - { - "adv_header_byte": "20", - "aes_key": "236A98706211AAF9BE9FF085882ACD8E", - "data_elements": [ - { - "contents": "6D6AC5C8256B7859373EB86A68E7F9", - "de_type": 748 - }, - { - "contents": "ED06337DA3ACC11B7BD86A0D315DA7A4EF", - "de_type": 703 - }, - { - "contents": "1639315FF6AAAA4B", - "de_type": 855 - }, - { - "contents": "785FD18ABF9AEDED7D3D407144A7BCE2F34444", - "de_type": 738 - } - ], - "encoded_section": "7C911000F1B2D3FF697FEA61F1D24313BA24DFB09004BA73F0D4A7915365382ABF284BBB970F4F4FD77A6B3F48CE433EDF5679495A60CC803BACE3039072420D0FE9C1CBB529280C72864F31A3523FE98BBD39AC48E3A47524E57BC2259AD362901721E8EB8FE1F563C6C3EFF3374A277553D9D41732D44A4CB97BFE1F", - "identity_type": "provisioned", - "key_seed": "2D8D09BB3E1DFAB0611039A1BAF74D5258343FA303332251F86EA7D1FCCBA814", - "metadata_key": "158E2E60C7F45BB9D6487B4BB3984DEE", - "nonce": "9592919D3E310674BFDC2E9E", - "section_mic_hmac_key": "69D008503467933362AFA9AAEB534D22839A8946A0A2AC717553CD50ECBD5D44", - "section_salt": "F1B2D3FF697FEA61F1D24313BA24DFB0" - }, - { - "adv_header_byte": "20", - "aes_key": "52A4E397E30CD9CC7494F1FB77E608AA", - "data_elements": [ - { - "contents": "8C3E52853DF5586EBD", - "de_type": 413 - } - ], - "encoded_section": "41911000BC844E7B944BEB5585FAAB4B71443FE990044489F0D699085E6ECDBC45D5A180550578468BF5FCAF01E7AAFC8612A47B5B8BB81A82E844D8EF05E4B223B5", - "identity_type": "provisioned", - "key_seed": "4975391685B7E23B969FD2EAF9ADAFFDA9E54345F6C978691019DFE171CF1AEE", - "metadata_key": "ABBCF6913AF3396D4698A3D3ED9C844C", - "nonce": "6DBC8A54F98C20F59D424BBD", - "section_mic_hmac_key": "7DA38D6F5976FA186530C3259FC16951302C45E1A182A5B856778AC15D261A63", - "section_salt": "BC844E7B944BEB5585FAAB4B71443FE9" - }, - { - "adv_header_byte": "20", - "aes_key": "81775F391E97501F10A06ACF2C1E1E8A", - "data_elements": [ - { - "contents": "E0E9135120FB76345D7F8649D99DCF21082B", - "de_type": 209 - }, - { - "contents": "A8930F2B30AD1020C7719732557A115B73", - "de_type": 702 - }, - { - "contents": "8F573C102D81EAD9DC", - "de_type": 608 - } - ], - "encoded_section": "6A9110005135798EFB48BFB42A2542E5EC84F8BE90024EDE7FBED7BE6DB4BF57CCAF6B79B42AD2AE82EF17209B1118B1B9BC30E3DC7EE47CC74BE402A40786226E6662CF3C582AECFEDB6BD9FDD87CD780D34B7CC7708714ABD30875A945E6592FC178421FE73B85293353", - "identity_type": "trusted", - "key_seed": "CEB5046E0E41EA2D087D6BB2584FC8F5AC4AE70C3F262AFA2FE83BEFC6A7F96C", - "metadata_key": "09F8FB1D817845D11CE0DD441FB6E6B5", - "nonce": "70D102E7E612845E49DC9A32", - "section_mic_hmac_key": "600AF01CC5117CB4AC58D49609CA3235EA0ADAC22B68D6FEA6973397744E7100", - "section_salt": "5135798EFB48BFB42A2542E5EC84F8BE" - }, - { - "adv_header_byte": "20", - "aes_key": "F3293976BEB4E1EA2904909A54A90D0B", - "data_elements": [ - { - "contents": "AEA9748A963B21DDDC0B", - "de_type": 82 - } - ], - "encoded_section": "41911000CCFD0A49D64FB8913DB3533CD842618F90020B1F2BE6DFF4647003A4CD20BEC2045A9BC3557018B6D8D1DDF5BAF68CBB0043BFE6F7F3A16914E72473574C", - "identity_type": "trusted", - "key_seed": "F7AB19164021C53FD3F406A4F4617A396FBB0B2083680D6A70F0FA93ACE0F337", - "metadata_key": "43CAC734B4E59E6410B789DCA22E05B6", - "nonce": "14B2E4D0A4BE88CD3AEEB9FF", - "section_mic_hmac_key": "6D816BF43B74326FE8A2A88B37CE383F8B46D0C126454936586F027EC60C489D", - "section_salt": "CCFD0A49D64FB8913DB3533CD842618F" - }, - { - "adv_header_byte": "20", - "aes_key": "375B33A2656E245BB1ECD330174673A4", - "data_elements": [ - { - "contents": "54A8E89BD5EEA62D46C39CEE1D60ED4733976A", - "de_type": 596 - }, - { - "contents": "", - "de_type": 599 - }, - { - "contents": "05286DB66919D9F031C704E925CBF68E6B8E", - "de_type": 766 - }, - { - "contents": "95B7B05F119963240B933C337C6FA9B6", - "de_type": 336 - } - ], - "encoded_section": "76911000AB7FA706A14892CDC9CED6E9C13C028D9002D26550BE730945C1CA0C220A658856FA14430A49D45BCEEDE10DD1CAFD274BE5FD828116B8E3E3D71A3F679486A30D832958AD1B2E1415BF7F111BF4F6CCF94634C904B46F5FB2482F8520F7EA10061C018B6C24891AFE186B8144EFB4981D1E79", - "identity_type": "trusted", - "key_seed": "D93D2A387F132BE81714405D487F9323099CD7089ED80FE06DBD5F19B9479AC4", - "metadata_key": "C249909E8C874421F56B5D5FD883F6D0", - "nonce": "3608D422560EBDF764ECC44F", - "section_mic_hmac_key": "ED742AAFE3D39273AC51EC4E94A7E5AD3EFE52D36E61F96ACD446F2A9C77618C", - "section_salt": "AB7FA706A14892CDC9CED6E9C13C028D" - }, - { - "adv_header_byte": "20", - "aes_key": "9911435E27099CC033ADA0B809A9BA61", - "data_elements": [], - "encoded_section": "35911000DB8B02B57082EB58CC198556EBED435E9004A72315469AD264409CF53387374629C4683B4C7D198CCFFA95ABA332D9EAD095", - "identity_type": "provisioned", - "key_seed": "DE3FF3C256080ACA31DCE848A0EF6DE573A584AC3FDF00011207692CBFC71AED", - "metadata_key": "A59DB751175865B4DB9CE9F5791D48E2", - "nonce": "22CEE3D3F35609F5B04F2681", - "section_mic_hmac_key": "88118CAA46862E8B57E83C23387C88F232BF22E5772D80E9EC15B75DA160F25F", - "section_salt": "DB8B02B57082EB58CC198556EBED435E" - }, - { - "adv_header_byte": "20", - "aes_key": "78237E429DEB7FF64A0CF0390C6B5AB5", - "data_elements": [], - "encoded_section": "3591100092F6C10DFBB105F88D53E46103584A369001CEBC52E442697CE7C0439351600F775089647E153AA0A20B8E0446CF188523A9", - "identity_type": "private", - "key_seed": "3343E7EAA3F48E39F01E5E8BDD5082E6DC4FA5A75E4FA570E717EDECAA9D26C2", - "metadata_key": "65D3B6A2568AE0425F06C2E1A5F75F61", - "nonce": "B44EB10C11D792A4474CD363", - "section_mic_hmac_key": "FA58129EF913C31E017D2583EF3C53A6921C4C05F1F46DFAA29644E1AC8D13F1", - "section_salt": "92F6C10DFBB105F88D53E46103584A36" - }, - { - "adv_header_byte": "20", - "aes_key": "718BB6207F09ABF1767C88964995A316", - "data_elements": [ - { - "contents": "41B733343BE9A40195965F3BE53A9E8DA772F91D", - "de_type": 38 - }, - { - "contents": "CB88998C5B3ADC6834216F607769", - "de_type": 644 - }, - { - "contents": "E2974A19DE611A27FF0AF9D27042B8073563FD2119C828CE", - "de_type": 587 - }, - { - "contents": "4FE69B", - "de_type": 58 - }, - { - "contents": "16A152105C8A1CF879C2838EA6CF4CC9", - "de_type": 494 - } - ], - "encoded_section": "8F91100054D79FCDA215B6D37188275A6D71B49C9002E7ED4C98D0689465F88315C5E1E4CB1C994AF90E6DB73F55D62E14F5F6102EAEC722DD4B819BA652CDA67523910FBF4AD135A678F170DF68642B9A3E651817C280D56CB333C492B7B7C6EEC2718D16DEE888255E9470E50548CFDD8EF3FA1BE96BE3FC9206AF1E806AB72D7CEB2556A84DED90BFB26C7473D6A3", - "identity_type": "trusted", - "key_seed": "87AF0A342940CCE0D8A7C250CEC581D677776EFE684FE7A461538D306F79595F", - "metadata_key": "ADC6D21008E6C6F9C6140DD2CA7A2D74", - "nonce": "DEA185B8030CB125ACCD1991", - "section_mic_hmac_key": "0B96048E575A8DDE941E0BFCC9AF72673B9E59D0EEE1D410EA3B5D7059D8CE43", - "section_salt": "54D79FCDA215B6D37188275A6D71B49C" - }, - { - "adv_header_byte": "20", - "aes_key": "AD321D407A23FC1F3DEA4AFBFCE666D8", - "data_elements": [ - { - "contents": "DE6102C7908322A68E36094307406EFE", - "de_type": 130 - }, - { - "contents": "D811C6749B", - "de_type": 979 - } - ], - "encoded_section": "50911000EEF15DD154F1CBB12B876AB7E4C28C519001BADA4DD563CC46E682BE16A078D5AE079DB587A78C9BD6BB37621F9F8EA5B7FB490D6857D3C3D3BCCABDF00E85438DB6227C002BFA7291D54E5FF9", - "identity_type": "private", - "key_seed": "9B702205F66C701BAE43D0EDDF8C3EAD92C80A3A8583C3397E7A3371758011EF", - "metadata_key": "FF0BEBFC2C42168A47B3474D3439772F", - "nonce": "D225BF85D21A4C34FE6B6AA8", - "section_mic_hmac_key": "9CE75F27AC9E99BEA41587BFFB701F9D59793C68127183BA3BA38D219DBFDD1F", - "section_salt": "EEF15DD154F1CBB12B876AB7E4C28C51" - }, - { - "adv_header_byte": "20", - "aes_key": "D62FF5F858D26914C62F3C93ABD608D0", - "data_elements": [ - { - "contents": "72FFD6C3F4B1B90771A08D281085", - "de_type": 817 - }, - { - "contents": "A4F94F7BEFD75D29A53C2ACDC0A908C2F5AA0768", - "de_type": 618 - }, - { - "contents": "0FBBAC5329C023", - "de_type": 729 - } - ], - "encoded_section": "6791100097FF92E30C6B6E08B416A150E2099C2C9004A34006E38EDAD68F7BBA8294E12E9F92DF7A91259AFC5B813BE7A4FD8601959912E5B2CFBACA99A2460EC2CC0F6DE999F47A7580B9F0CEA2E0F882836864E82CEC3DF6F890269AABF65852CB9CF026D85452", - "identity_type": "provisioned", - "key_seed": "393F3DAA73636DE22AF63B869FFC970C1DAE302372E51F35BAC421F3C354B666", - "metadata_key": "CA8F91CB3DA7A5A37E33F851D93EBEAF", - "nonce": "A521F5DAA92BF1C1654569ED", - "section_mic_hmac_key": "67AADDFA3C1E18B279906DB7987D29EDFEA643D678FA1AB4987A0A1D610005B0", - "section_salt": "97FF92E30C6B6E08B416A150E2099C2C" - }, - { - "adv_header_byte": "20", - "aes_key": "EF85681E26EF87C8D2A1A3EE56FEAD2A", - "data_elements": [ - { - "contents": "C24BDBD7E3697F223F1621217A9C36DC9394EC33", - "de_type": 335 - }, - { - "contents": "C1", - "de_type": 14 - }, - { - "contents": "E4231F2308EB41", - "de_type": 902 - } - ], - "encoded_section": "5891100037E9D4686030FBAC57D3FE42D92B096490014DBC20227A7388E74D0961E8674691D101607D944F8AAD12C950188603894DA02D5FA3698A54DC40598F44313F297CDCCBC1DC14CD32D267267747B0B125D91A89A557", - "identity_type": "private", - "key_seed": "4A289EAEC36BE20656071FE87F8A55155D8A893815038B9ABCBAD3E72DB0C8AC", - "metadata_key": "C0450DFCC6AB17837C56EEDBE57D62A8", - "nonce": "A9FA4AB4C0929CF2CDEDDF34", - "section_mic_hmac_key": "8D45B9467DF17FE0943F155851C70CCEA0555BD59453503FF6A861F9011EF853", - "section_salt": "37E9D4686030FBAC57D3FE42D92B0964" - }, - { - "adv_header_byte": "20", - "aes_key": "BAC1BE39B5BE69F29396EF5CC41402B9", - "data_elements": [ - { - "contents": "AF9A279790C0EB79F07F700C1CED8CAF60B72F", - "de_type": 101 - }, - { - "contents": "14F153F824", - "de_type": 463 - } - ], - "encoded_section": "529110008ED27B5A64F8584EE798DA971BB3890290023D54202AA267D540AD159401DD2CC11E1F387FC4F90C9BA19D810C095D415CDF08EEC637B9CB2DF1259229CB2F02F894D63404B428C9AA33BDA7507601", - "identity_type": "trusted", - "key_seed": "9AAF4E2D596A7B4CA21DF9312AFD43A63FA8FA727DD60273072C4C4C0D472E3C", - "metadata_key": "5F68164865C2DFB852C81375C3D3D5E6", - "nonce": "4F23D7E91CB8E22BD3712FC1", - "section_mic_hmac_key": "0BF5C29B16B353256F793BBB4F1C8C52597D3F1C2EFA9D61EA46CDFDE84797C7", - "section_salt": "8ED27B5A64F8584EE798DA971BB38902" - }, - { - "adv_header_byte": "20", - "aes_key": "68A9C01E867B79A4CF5C2B9B0A5AF91C", - "data_elements": [ - { - "contents": "AE6F1048CD", - "de_type": 505 - }, - { - "contents": "092DCE72E9C606136151791CACA850F34040EB06480609", - "de_type": 524 - } - ], - "encoded_section": "57911000E8C86E9B41DF4F3B937952F49BC6738B900232D03070C79D80DDE8C1E0999B4434DD06A23FCF22CCD7DCA29E5074665F99831137706D16C0200B8B4598365543AD4BD647A682DD8D226897C1EB8F43C443DBD6F8", - "identity_type": "trusted", - "key_seed": "580ACE8B6CDE7180BD4AD61F486AB6AF65F04174A9E10C982CA1BE480E27085B", - "metadata_key": "E850D26EF14BBB1E7B3D1A5F64A50353", - "nonce": "2DD94E374A847EE945DCDEDE", - "section_mic_hmac_key": "597E20CCB0FF2807C1B8217F21115FB753F67303B79DC679094D7105C5EE8A16", - "section_salt": "E8C86E9B41DF4F3B937952F49BC6738B" - }, - { - "adv_header_byte": "20", - "aes_key": "CC5210E1AA93721F6A77C03B0F1460F9", - "data_elements": [ - { - "contents": "31B8D3BD3DAD8D7EA787EBBAAD32", - "de_type": 105 - }, - { - "contents": "52CD1D16C9C10292F325BD", - "de_type": 679 - }, - { - "contents": "9AA553097F55186B693EF9F811255D4F9E33012D", - "de_type": 70 - } - ], - "encoded_section": "69911000B0B06E5BCBFB897F867D1A98860C88819001968D65E73BFDB4A9C8D0CBCFD94F0AFF86A172DBA041C9B4819B60AE15C84ABF10167323F72BCE73348C948BADCACA60B31C01DF54A03A41FFA1CB83B1724E34BA74D43D17956AEBD6F5E9411F6D801A30C545F5", - "identity_type": "private", - "key_seed": "BB1C67EC1220D0A1CD718868B6DFF75A45F535D79358AD7417E98F584A520850", - "metadata_key": "5E11BC73AFA36ABB0FA9D177F470772C", - "nonce": "10C1E9BEAA44D044A6A52DA8", - "section_mic_hmac_key": "8F47EFD6981006EC099088AA42864E13399300C42A22D67FE00540745BC434D7", - "section_salt": "B0B06E5BCBFB897F867D1A98860C8881" - }, - { - "adv_header_byte": "20", - "aes_key": "636CF984B555E396E1ABE06B45A0DC9A", - "data_elements": [ - { - "contents": "26124A707B14872CE3CCA803962D1E8E", - "de_type": 356 - }, - { - "contents": "5BE121EE1535F68B384B2048", - "de_type": 191 - } - ], - "encoded_section": "5791100091150893740502FC52626D5C1FE1D97B9004D692F649B521B08446966B43B3A0E2853FC66A18FD044B2D9FA619580671AF9A093BC9C29AC2285193C8377E231E4E378A0EB12B69F309BBED412881C06054211F79", - "identity_type": "provisioned", - "key_seed": "9F10722920D514FCD00582382A3D744B7513089C4ED4F0F762E62F079817EADA", - "metadata_key": "CED359A792C26F42583568633F362936", - "nonce": "AC3820DF4711726BD92A95E3", - "section_mic_hmac_key": "73CFEDBC2C7DCC199778704504D8406E69DEF3850E9E556E65264FA5C0F72049", - "section_salt": "91150893740502FC52626D5C1FE1D97B" - }, - { - "adv_header_byte": "20", - "aes_key": "BB72B0AF2C215797791F4813246EEAAA", - "data_elements": [ - { - "contents": "B560FB4055782B29002780C1C79A92C3AB5C94BBFE1D30", - "de_type": 704 - }, - { - "contents": "D9D67201EFBBC989BC73CB82CE5A54BA30270BCBCD16C3D918C46C8FBA", - "de_type": 759 - } - ], - "encoded_section": "6F911000C4FC89ADEB54417C2145D31AFE590E67900479850A6176A11C5005C1B816084BBBC8E1B96A5E84FA83927CFE3F85B13CA15C78C4E487AF94942D9527A4EE40FCE291F8A4076FF3285DBC70EB2AE12076384B309C9DB593EF97E5952F1A878E9357C5215EC4CA7382A07821CE", - "identity_type": "provisioned", - "key_seed": "4F5BCFCBCE781EBD9353546FEFDAB4123548E63980050C1FB2FEBE745EFDEFFC", - "metadata_key": "18CE930F2687B1C72063C2B147ACBD0C", - "nonce": "09C9C088DEE34D597B83255B", - "section_mic_hmac_key": "3BD3CBD58CE94F98266BE570B2897F0C0CDBC8900AFB76E0699315F0132C8D5E", - "section_salt": "C4FC89ADEB54417C2145D31AFE590E67" - }, - { - "adv_header_byte": "20", - "aes_key": "9BBC179545C4C8661833BFEFE25E4478", - "data_elements": [], - "encoded_section": "3591100018CA84AD571B443615D490F5A1AB791E900287C25FBD0A1AA47A74D7960394D449914CF5F364A1DBBFEC57B7447A38AD0152", - "identity_type": "trusted", - "key_seed": "0B5BD58A7DB4DAB27EAB2B71CE802751442437C426E163735196EBDD9EEC98A4", - "metadata_key": "21E42F417AA748179A50406477891087", - "nonce": "22A25ECB407B6DC73A8BCE1F", - "section_mic_hmac_key": "35857C6B5BFBA20A9012E81B452C95D5F62B7D429C9F250F6FC8C96EEFDAD338", - "section_salt": "18CA84AD571B443615D490F5A1AB791E" - }, - { - "adv_header_byte": "20", - "aes_key": "29912DF85FEE4E2802F3CC758240C118", - "data_elements": [ - { - "contents": "20EC521C467D60C62519AFEFFAB2989DA34F609D7348CB0648", - "de_type": 881 - }, - { - "contents": "7CDFF605A49D2327C04C9523E972", - "de_type": 339 - } - ], - "encoded_section": "6291100096874E513BB028EA8D3147662E898C929004510A31F7EEE22BBAA1A676F50D87B736D02CF8AD40A2FC01F73D61050AF86BDD26889F66B6C7811E98013B10549BA699C5B0FF6B97BC95CA461512A91C6CD748A847E8A06250284F89D8768282", - "identity_type": "provisioned", - "key_seed": "BDBB0B95B3F933B91F05CC9ECED4DD468E3174109DEB7A4F0783C40F39E20761", - "metadata_key": "A97FB828B07A9D327D5567152634D0D4", - "nonce": "F8BD43493933BD842C97F146", - "section_mic_hmac_key": "32031801363FBE1A50288A6A9B0756EAA7CC2D653CA0B2AAF345CC13884DD2CE", - "section_salt": "96874E513BB028EA8D3147662E898C92" - }, - { - "adv_header_byte": "20", - "aes_key": "5D161A5D965DE072EC72B7EAAC295469", - "data_elements": [ - { - "contents": "2499FFB9C498F2", - "de_type": 884 - }, - { - "contents": "941AFF758DD7D3B66EF8321874A7834A7E7F51BB284122405EE0", - "de_type": 463 - }, - { - "contents": "74C7CF3DF00CA35B", - "de_type": 435 - }, - { - "contents": "E07BAF5D40CA3AE208E6BDAFF05B4F9E0112559EC495", - "de_type": 2 - }, - { - "contents": "58E1ADF13A6F2383CCDE989D6CEB02EE47F1F3", - "de_type": 396 - } - ], - "encoded_section": "9591100066B9B5E27075D2EAFB9B4E2E4159CA659002025D80ECE442E6A3D7F5DF17BEE9E8AA64D2904E04D09898D04EEB323B64C9AC0DC4F9FA55ECD3B7D58DEB3D9FD72FE1D8A213CCD6DFE89D053B106AE0F7A41844294DDAFB6E22A35F6F5A1251CAE0829609A463D966DC5C2BAEBD166B166CEBF5E3471EE3EAE4DFB5A594C0C64ECDBB00D301299F9782000628F11738B95006", - "identity_type": "trusted", - "key_seed": "5AEE4779ADDC954FAABA8C967AF32BAF74DA2E3790FF77750F20A10C300C66E9", - "metadata_key": "5819227E20E94984AF636A055E65EDF1", - "nonce": "627AF9F6E80A568473F0D41B", - "section_mic_hmac_key": "97182D1562F3DAC1911CBE791388036D5826EFC5BD2C9B7729555BC39D6300B9", - "section_salt": "66B9B5E27075D2EAFB9B4E2E4159CA65" - }, - { - "adv_header_byte": "20", - "aes_key": "8EF15FC5E15B86747BD2390DFD8D8FF4", - "data_elements": [ - { - "contents": "5F99290FC42275AC698492E2263094B80F692233DB0DF8644B", - "de_type": 845 - } - ], - "encoded_section": "51911000474A64D6CC5E1B015636E3CAF848E92D90029797772EBCF190224F6B5193FC0573554FD8D1B7C2B8DFB0C2344080EC5DE79A14650738DB3E375AB1F2416A0E091F2DADD7710C6731F9D2F4BC1ACF", - "identity_type": "trusted", - "key_seed": "3807E53D0E4A6A3C131FE2D9A12F3A17C9A81E206DD2403424D079986548F36D", - "metadata_key": "649BF41A962338BDCAFB3D6EFB39F30C", - "nonce": "11EFABF3B773890FD705DC45", - "section_mic_hmac_key": "BC9DE8BEFBFBFCEED8132F0E74A7FAE68CCF1F3259B42670C074355E57771EC6", - "section_salt": "474A64D6CC5E1B015636E3CAF848E92D" - }, - { - "adv_header_byte": "20", - "aes_key": "D87966196010EEDAE937B516E77C110B", - "data_elements": [ - { - "contents": "D72414FDE144", - "de_type": 693 - }, - { - "contents": "89B82594CDEB3253E8BE54402F4EB47427FA", - "de_type": 139 - }, - { - "contents": "59F5D560DCB71A1A9AB340270EFCCC791F60ED3E5C16C9", - "de_type": 361 - }, - { - "contents": "5E8317B7EF6B2304CE733AF9AA4303", - "de_type": 347 - }, - { - "contents": "6B46914ACC05AC520CD86D64D95EF8B0E3B52684AC19C7", - "de_type": 217 - } - ], - "encoded_section": "99911000550E90767EA297708A890EB778F86F42900194407433CAFDBC096242CBB630D9EFF2428967372331DA563029EE56D7736DB1C6B0F4171C6AACC70B165A1D7079B7213A484AC56B751F106EA890EE1F44B1DD84B03340FF64DE0D86EDF6E3C266B6E29F973D7DA9EA80DA5504E23FA9DEFB13DF26D97D8AC03B102233E7A400716212664A1A66A04360810288591BBC53D82755D0B7F4", - "identity_type": "private", - "key_seed": "5E128361F047F517713A5E7A9FBDFCBB8A65431B0FD54CEA276C15AA38738D00", - "metadata_key": "6219FC039F504E84C27E0C30A7922D50", - "nonce": "219ED909CC34B1C57EB81FED", - "section_mic_hmac_key": "80144AD3F7356F4D118216C943ADE3CE6A4C1CA1AC36CCEFD81AF75222A0C277", - "section_salt": "550E90767EA297708A890EB778F86F42" - }, - { - "adv_header_byte": "20", - "aes_key": "ED1872743ABF1CE1C54B5924D8B523C9", - "data_elements": [ - { - "contents": "1EFD8A5E7097C3EA66A30F3F6EC8", - "de_type": 8 - }, - { - "contents": "70AA1FBCAEAF957AF9C114", - "de_type": 741 - }, - { - "contents": "727C6DA4BC51406D03", - "de_type": 628 - }, - { - "contents": "C80BCC953AFBD14D003F9C18", - "de_type": 905 - }, - { - "contents": "B3EC6F94CA366939C934FA84052FD4", - "de_type": 357 - } - ], - "encoded_section": "8091100002C4DA8D1B21BAE28B3F9A0EB5693E8F900493FCDCCF43EBF7EF19D4476026AE4F5241FE0162977FB70B8E376CEE57BC2A866306A3787F61E88D954EAF7060BCE7A3023C7683CD7EB4F9D15A14147EAF9FE39A0BF9863BCFFEF8F4F2E8AE52F06651E06E94F809CE32E06DC15434A3A3D7AF4E42BBF88EB53E9197D489", - "identity_type": "provisioned", - "key_seed": "3DBF4DD4A42D6FE76568BF430BC73BC5772762941753D48A76134021D17123C7", - "metadata_key": "B6B17BEBEA55CFA5B610047C599FDCB4", - "nonce": "9E2B3708BC702B007B2B49E8", - "section_mic_hmac_key": "F0E7F12DF72F3EF40DE46181DD19D3E673AEE02757529C53F3F6DF9F8AAEF663", - "section_salt": "02C4DA8D1B21BAE28B3F9A0EB5693E8F" - }, - { - "adv_header_byte": "20", - "aes_key": "74300AD75CB40E2D6CC26BF7C3EE29E6", - "data_elements": [ - { - "contents": "506CEBFF222CD35C949137A3A47D6FAD9620", - "de_type": 439 - } - ], - "encoded_section": "4A9110007816B4ED58791237D1053F88CD8B7B859001D1EBFF70B960E79E6DFA6A89359F991816C253BB5B09AA2E98748E101D8BB2D18D4043847E353F85C82A586B92D5E7F0DC03E6CD14", - "identity_type": "private", - "key_seed": "8CE98EB290087656B04E4996CBF4007E92E653CAE71AF06D479B96D45B83447B", - "metadata_key": "81A2696BD7D21903EE2D63D2C4C44E4C", - "nonce": "CDCBF3E9E0E3EA002A004AFE", - "section_mic_hmac_key": "48966839EED698298B8544D0FABBB3E8009D9D67CE88CEB6F29B1FBFAEFB7C47", - "section_salt": "7816B4ED58791237D1053F88CD8B7B85" - }, - { - "adv_header_byte": "20", - "aes_key": "256EC73F1FAF17723C9B5C6062749FF7", - "data_elements": [], - "encoded_section": "359110007897264056B8ED625680B2F5124C30A890045D4D46423E9067DF2DFD36F3718282724748E10C6E16DA2C039F9C30D9FF6054", - "identity_type": "provisioned", - "key_seed": "D458DDE6E939B3C03B8CA27BE7D624D70F3777FB31C8278152C3C0161269A228", - "metadata_key": "76BCF4EB8C12033E8BF0534B8A6AAF4A", - "nonce": "1451BFC0DA68DCB2E0FCB937", - "section_mic_hmac_key": "DDAF42B3C3AC34F3E8F2C882568213E333A91F0A049E79AF52E98669048CA81A", - "section_salt": "7897264056B8ED625680B2F5124C30A8" - }, - { - "adv_header_byte": "20", - "aes_key": "1599363CAC85444B80B2BD6F32B44889", - "data_elements": [], - "encoded_section": "35911000D8624D1EC90B225B457D22AF6D8B4F799004990761D38053D068BBE94F66F9968E14BB793A96B05BA0F4716C0A7814D331B0", - "identity_type": "provisioned", - "key_seed": "7CF0C36D0E587661503F8F70B8F3A06AEA7B6352E843387F353CA8355EB92ADB", - "metadata_key": "A54230D1BAD378D531DB91F517D11568", - "nonce": "D25B10F1899F9A9C56648C1E", - "section_mic_hmac_key": "C1A07E6C0ECA629D1ABB6CF5D6175F97E97637756561930B256BB6891012A830", - "section_salt": "D8624D1EC90B225B457D22AF6D8B4F79" - }, - { - "adv_header_byte": "20", - "aes_key": "3EB28DFBFF8CB955CC44F68B0085F70E", - "data_elements": [ - { - "contents": "8511547C881A7F7036FA2009F904BF", - "de_type": 42 - }, - { - "contents": "7C4430D434907C017DACFD336A161E70C10815B6", - "de_type": 284 - }, - { - "contents": "15C1124EF76C2D9BB61C", - "de_type": 132 - }, - { - "contents": "3E3B0BFE93189B50", - "de_type": 694 - } - ], - "encoded_section": "759110007F2CB662B15FBA6D7C18AB52889B266D9004CB724FEF84FE55FCB1A2B571C77EE17C930A5F6606F40EC38F4241A6B287A8B1EB443F7C013B34B3113D193F884B120F0AA415452FFAAA0B40B78DD80A09858F2068537D2AC8F8DF750509B9D52A4B9B39F10C2CFC42A9B90FC762945BC31CAD", - "identity_type": "provisioned", - "key_seed": "547C965E115345BADE7FA439398A1618870F0392671DEDE9944FCC693DBE32B4", - "metadata_key": "C55B065D5B03C633C7546FFE3043FB8B", - "nonce": "888A5C195BCC1327C7DA9E7A", - "section_mic_hmac_key": "F672CB3E86B8E87B727CB0814C7AE096C3E7C7EE2398D1581847C26951486BBA", - "section_salt": "7F2CB662B15FBA6D7C18AB52889B266D" - }, - { - "adv_header_byte": "20", - "aes_key": "A952EA928E55FAE45B612EFBB2E92897", - "data_elements": [ - { - "contents": "A39AD60114B4E470CD6E5B1981F6D94FDF21E386A957B3", - "de_type": 11 - }, - { - "contents": "30309360211C7E94BC8B3692BCE38EE888ECF197C594C3D07D", - "de_type": 10 - }, - { - "contents": "66DF42C0A9CC3385053676451C23276C1CB169D74DDB1C46A6EDE2C89707", - "de_type": 610 - }, - { - "contents": "550E675F587E", - "de_type": 554 - } - ], - "encoded_section": "939110008F8202EF37CD727B74948F6A5205650390045048FB340FCBE272C4D667BD6691E08084C56D24D168EE7C6B3AD228DF31ADD89B1627C7511ADF1E12882ACECB1C05B49539F332C01F0C2778F039A5727864A5FA46F9030820D06D961123CBDED94746017E6B2224D43BB304D590F12343258BDCF84F691600B58C18025956190BD91D359B1654D5862590962E89FC3541", - "identity_type": "provisioned", - "key_seed": "D75311C9FD54732B0D1D58E8C13D69582675936BC2D4B948E4DA8B8FD4E4EC19", - "metadata_key": "44A8ED043D7B7A04048C04871D04BF28", - "nonce": "39A11C1233C3887D0FE2FF95", - "section_mic_hmac_key": "0370E5CD2CA4944C5633BDB505F471ED4ABD6F9E0803BD57669BF1A096FBFAF4", - "section_salt": "8F8202EF37CD727B74948F6A52056503" - }, - { - "adv_header_byte": "20", - "aes_key": "375CC4495D0E6037B4A269A5A4EA302C", - "data_elements": [ - { - "contents": "E51613F10B7423784CB6E3FF2E58", - "de_type": 683 - }, - { - "contents": "ECBD79DDFA8130DCDEF28AD2AF40C6A8DBB16B2972", - "de_type": 264 - }, - { - "contents": "9FD18CDBD2FC1FBAF9B317FF280956", - "de_type": 617 - }, - { - "contents": "8871908BB20E8F", - "de_type": 918 - }, - { - "contents": "DD8DA6F96A3751", - "de_type": 721 - } - ], - "encoded_section": "84911000C7A3432633031353A946F0684CFCFEBD90012BD99B1A635B8CB01DDBBDB46AFE8742B053F93A65C75293797C523784EAE07488134AE32476E0F698D440C3A0A389DB48B6846E2D42A89584741285C09301225752A1A5C8152E010337BBA3ECB3C15D6893C2B2CEAB1FB452D50E5990EA1C9B007C08642769AF82551F3FFA44040B", - "identity_type": "private", - "key_seed": "D948351CA86C11F94DFA31FC2B86C7EBD32251E770E243B287D5C03630A7A4B4", - "metadata_key": "0F37FFFBB8B3BF85BE6B4A5D7AE60C37", - "nonce": "5A8953196DB0C6B086052AC9", - "section_mic_hmac_key": "6A6CE54F7E0FCB42716786C56294DB3FF4839464EB6D6DDE3037015BF42591CD", - "section_salt": "C7A3432633031353A946F0684CFCFEBD" - }, - { - "adv_header_byte": "20", - "aes_key": "2276BD761EED06699E8A4C1B005226C8", - "data_elements": [ - { - "contents": "09D7C7411219259A530E4207", - "de_type": 202 - }, - { - "contents": "E6206D70CB69117E5B0CFC6484E5A9F6E6", - "de_type": 335 - }, - { - "contents": "124F723ABCB0F46AC2D9904E49F29C72F6A37A6F1C", - "de_type": 173 - }, - { - "contents": "F03BE2BA870E9DDDE0A20C37F7C3C513418FC8595CC2D9", - "de_type": 162 - } - ], - "encoded_section": "8A9110006FD81C4F4977A61EA77802E4AE331B1B90044590EF69F794BECCA20B04E1A5794A8FE0BE6B353BAE140B8A37594A011AA936FCD209E03D522D1C147E321147E9B33735F2CA413B5C945091EC1AB92537B781F26714EAB879BF33E801BE58488C11306DD259B63B1F05FC146871978B17CACF8AEF88D021782A6DB7112D4C930FCA66626E69140B", - "identity_type": "provisioned", - "key_seed": "B3E1C7E5933E243B2457C3493F6C62D88640DF85591E1A370EBB5ED1A7E87DDE", - "metadata_key": "584C3B455D31A6EB73CA6286A6D1D677", - "nonce": "7C59A6FBC27521B60FDE3D85", - "section_mic_hmac_key": "4FC402F911776BD4BA7E1B934A76823AAEB91AEAE70F229149737AD2446C8721", - "section_salt": "6FD81C4F4977A61EA77802E4AE331B1B" - }, - { - "adv_header_byte": "20", - "aes_key": "ABD1E3B92ECCC94887008F9712C8B92E", - "data_elements": [ - { - "contents": "53AA992BF504934429F0D55BCA57E7E4DD02BF1C51", - "de_type": 77 - }, - { - "contents": "37", - "de_type": 41 - } - ], - "encoded_section": "4F911000117F8B155FCF545D9DDE2E2404BF08579001181FAA51DA6430295D27D32A8894FC80977F9FBB2260C5F335DF5E2985B1E9DF677F8DF40E3DD10180E31FD4A1E640AA81AD2D59ED29C73E0DD9", - "identity_type": "private", - "key_seed": "BAE413A1CB297D1B55956EF2E3D47463B15721D83113EB265CDE9742DE57D1E2", - "metadata_key": "E118EB2F2448E831DCB2F01211D4E299", - "nonce": "641B644EC4576653B4ECE6BE", - "section_mic_hmac_key": "7001ACCF2A6FE829E333351CF9500F0EC9F144AC2432E2D4E65BA205B5A2A083", - "section_salt": "117F8B155FCF545D9DDE2E2404BF0857" - }, - { - "adv_header_byte": "20", - "aes_key": "0B886C679F8368F71B69095633FD827A", - "data_elements": [ - { - "contents": "C57A03111A582D033BA2F0BBF50F0698BC008461C715", - "de_type": 648 - }, - { - "contents": "0C95F385C694E2BC55C219B0086BA9F8B64C0633", - "de_type": 415 - }, - { - "contents": "C9826C977F5D51", - "de_type": 246 - }, - { - "contents": "B88067D984", - "de_type": 989 - }, - { - "contents": "98C5E507657F0B36CAF5D0EB02A5B30F1087", - "de_type": 663 - } - ], - "encoded_section": "8C911000AD6BDCEEB60CC9801003D4F71FB8AF0F90049916A86D88CC6C404111A7D9075FFC0C699303B2BB1CDC7492495C139069B609E02C45F3F2F5D1F11C5CC45EAA610AE5F9A3085D638A8D774E060572A9E8E276FDC2B9EAFFAF23469097068D9F2AA77BCB5F548EF636B8BEF3C02495DB690858EA8A13C78501E64C54D05155EA488719C539D7B9060048", - "identity_type": "provisioned", - "key_seed": "B323DB96EBC1CBB190E305EBE290EF7E600D3D3E7D23688DC2C8C23B4EFC7A4B", - "metadata_key": "6436A7FA7D38F566B85179BFF2E4DA68", - "nonce": "43B0153AB9B6FFB0DA670B28", - "section_mic_hmac_key": "88BBCFCEB5CFAB8C69C5C978C8C21758ADE72E557C108CDF780367F6456C85B4", - "section_salt": "AD6BDCEEB60CC9801003D4F71FB8AF0F" - }, - { - "adv_header_byte": "20", - "aes_key": "E4E6282E18B2700912371FD299648904", - "data_elements": [ - { - "contents": "6E", - "de_type": 875 - }, - { - "contents": "3E7F165B8725499C73A790", - "de_type": 547 - } - ], - "encoded_section": "4791100001BF56D7253FE9F2388222BE2B414EB49004A2C3ACCC4EEFD9949E6470223F1085EEF12CA22DBF4E5A9DA978E44AF3E93F6142BE9270F59E188FEF58BBAC3BDCE8413351", - "identity_type": "provisioned", - "key_seed": "CFF5A7B58AD3CF1BF200E0874E1E404E0B8EC0BCE8812F1FFD4537E2330BF4F2", - "metadata_key": "C048921E6EE411AD4698E29A54BC6B4D", - "nonce": "8D23F89851021F5141478E33", - "section_mic_hmac_key": "1988C5772B660124148F05733A326F0F0C29DC301F2989294312F41C56292A59", - "section_salt": "01BF56D7253FE9F2388222BE2B414EB4" - }, - { - "adv_header_byte": "20", - "aes_key": "78DECA4E98143AB700746AACAE4CC14E", - "data_elements": [ - { - "contents": "F42C1F5B9E2060A6D4CDA7A2963F44A524BFFD5F0F2D69F3322DCF4B93E3", - "de_type": 359 - } - ], - "encoded_section": "56911000FE30CCFEF9FADE459409BCA8286268B79002DC0290C23BD3C7F0DCD8443EABD050919255A3755D0F5EBCBA7B540DA11DF0E844207B803710FBE088BE18847F5406B7711DBC583711B7930508B0B06F801CA9AA", - "identity_type": "trusted", - "key_seed": "F44873C8E1AC0DC8D63BC7CE805E543BA8A73CB83DF807B608246E14CFCCE5D7", - "metadata_key": "D0CB13BBC77450B18573A000E0E4B324", - "nonce": "D97378F4DF5B4D5249845D4E", - "section_mic_hmac_key": "11A63498ACF2C0D60AFEE3AD00117129582FFD6D50D3CA4A21CD3330BAF0B2C0", - "section_salt": "FE30CCFEF9FADE459409BCA8286268B7" - }, - { - "adv_header_byte": "20", - "aes_key": "99CA428E9B70F3A4F34CCE2EA3FFD1C6", - "data_elements": [ - { - "contents": "95651D83B5B463A0B4D7C3BF97C1CDFD9A2853DD216D", - "de_type": 842 - }, - { - "contents": "B1E32F", - "de_type": 633 - }, - { - "contents": "B44550D17D11C579DDE453A78F8E68", - "de_type": 764 - } - ], - "encoded_section": "6691100074678AA45A5827136A450437EE29F5E39004B94F1326A3CE7BDCA34AC253366FE37E6849758193586827933D9E096053DC06102448287A436069815904A0F3895C825ED3538CB827DF1B153E833F11DD926D4E5A45CD20EA0FE3FDB21A587C6C77638B", - "identity_type": "provisioned", - "key_seed": "71A3A2B3B223F84BE6E8595208384B34D0379E898137A3B5DC4F18C71502CACF", - "metadata_key": "8998FDB14463108B5A5F66FE289D13BF", - "nonce": "AFE96D0E4FF65C1734F9F99B", - "section_mic_hmac_key": "2222BA7F416FFEB9B14B07D5D2522EDDF0D2E82CB116D23699566520035BC6E7", - "section_salt": "74678AA45A5827136A450437EE29F5E3" - }, - { - "adv_header_byte": "20", - "aes_key": "3C5965394479133B2B0CDA3474935C12", - "data_elements": [ - { - "contents": "4C5DE6A43F855833418B23DE6E4C0AB9B8A6D1C581F15A683D", - "de_type": 831 - }, - { - "contents": "1AE2D41BF9064E056C22712044707CEA3EFAF26964D83E684D33CE", - "de_type": 355 - } - ], - "encoded_section": "6F911000BE86E394E730BAE02E2A22E8B54CF1A4900408EB6891543847E08002B13233D680C89B22F57320B4890E87533A2B4DFC30021206330351F378D93A7CE5051655B1EC84F8F4F68DBB327EDD4E0DA4948323F1B931733AA4D28F06238FF3622178015BB5C709094AC23A3E448D", - "identity_type": "provisioned", - "key_seed": "CFBB3B4D111CDF95E4AA9642D5D6C1611B8522D6F76C7B1F23C09DCE58133FE2", - "metadata_key": "3BFA93FB827970E4CD401DD9903ABF19", - "nonce": "2CFBAEDFFF07C80511FE4B1B", - "section_mic_hmac_key": "16B7AD3BB2B10A5B5D64ACEB9733BEDC6D0FD351E5D12AB36FF5FB283DEDF3F4", - "section_salt": "BE86E394E730BAE02E2A22E8B54CF1A4" - } -] \ No newline at end of file
diff --git a/nearby/presence/np_adv/resources/test/mic-extended-salt-encrypted-test-vectors.json b/nearby/presence/np_adv/resources/test/mic-extended-salt-encrypted-test-vectors.json new file mode 100644 index 0000000..52ff336 --- /dev/null +++ b/nearby/presence/np_adv/resources/test/mic-extended-salt-encrypted-test-vectors.json
@@ -0,0 +1,2213 @@ +[ + { + "adv_header_byte": "20", + "aes_key": "93FD082896AFAD5C02272FCAC7A4B19B", + "data_elements": [ + { + "contents": "F111383178463B", + "de_type": 965 + }, + { + "contents": "77A7CA333048119F23A460ABA89494CF7075CB3CC00E", + "de_type": 148 + }, + { + "contents": "E7B0F2", + "de_type": 596 + }, + { + "contents": "7B25D72AF20B8B53495E79E004108C7651C5F9CF07BDCD784874", + "de_type": 969 + }, + { + "contents": "938EF51180242B59D35CAD0DA09ED9FAA4D809BC", + "de_type": 47 + } + ], + "encoded_section": "02E628D03BE58B76606FD929A1D1F814D1163B0AE8EFD98D12D07B1F0D8D0203296CC45F4BB29B1B55859205A94440A19A7D13551244694A00388C0DF6B25405C6D2F6E15D8D1E4383D8D6A28BE510CB8941A7E44040B656C77670B9DE3612BD51E7FC7200C5CA9D4014BD784335CC4C377156D3E8B8750CDEAF086D82715EFCDB87F02C7F96D8EAF7E011169F2A", + "identity_token": "92220A2275B7CB8D5B8F7FDEE137C385", + "key_seed": "74BD3E08D69FBF2DC5431C5D2CC66BF83D602B54FA10334916F9457DD7F309DA", + "nonce": "C2B4EB521EA983D74D009C90", + "section_mic_hmac_key": "D1A28568BDFFFFB2D23AD8FAA174F72993AC0B5B23ED27CB27E7D99760AE368B", + "section_salt": "E628D03BE58B76606FD929A1D1F814D1" + }, + { + "adv_header_byte": "20", + "aes_key": "D371D308EB2FE0705ACBECFA55123A55", + "data_elements": [], + "encoded_section": "02074BA9EC8D17A3258489F865AA8B5AF679E71F22BA9938EDB211EA8163236EA810390E1A6CAE374F5446C039F9A031CE38", + "identity_token": "1F01AB90BD3A83FE37E74A301D415475", + "key_seed": "1104D617C7F480B1B5875CE6711FF91BC76FB208F8CD7D9F9A08AA9DB0FBC5A3", + "nonce": "4FEC96E42BE9C8CD180003A3", + "section_mic_hmac_key": "A5E871DC448A3B0EFD26DFEBA9EED9FC74EE02481C6704FE906D7A82E2BBCD29", + "section_salt": "074BA9EC8D17A3258489F865AA8B5AF6" + }, + { + "adv_header_byte": "20", + "aes_key": "97F371754AFE9C6F5438F467D077CEA8", + "data_elements": [], + "encoded_section": "02973AC46A20846531A220E935400EDDFEC74BA44660727C7B33874948C21A903010ED5DE380C975B9216B743277D73628A8", + "identity_token": "3ECB6505ECA3F0644780E4F848B8C914", + "key_seed": "777BA0008B38A5AF3F3CE15B1DB83B2612E312739447D525885DC0123FD347B5", + "nonce": "A848DAB9F824A480E1ACC319", + "section_mic_hmac_key": "FBAF9AF0C9E256671A99C74F3FDB9C17803ED334F5BB24C72FA056E05E3FFF12", + "section_salt": "973AC46A20846531A220E935400EDDFE" + }, + { + "adv_header_byte": "20", + "aes_key": "C401C5B15A57D0A26CEE901764560E0E", + "data_elements": [ + { + "contents": "F83D3AAF1566156FAF5128917CAD10CE348BCF", + "de_type": 563 + }, + { + "contents": "FB04C7C54945BE1F575F", + "de_type": 945 + } + ], + "encoded_section": "02ED1132C6CB2146F95306E0095791FB969C04AD11D18479F8A868273B5A3C3E1833592069C4077690D4A48D8F5F55C27FF3565B3D859F44E6D4DC439A38BC6063D55F20EA3494469131156AC1568BA18A8AE6322B", + "identity_token": "932D597EA1265715083C01111B233551", + "key_seed": "5B1F90B019BC982CA431E8CE303F506E192913E9E0D9E7AF75936F1A8336E29E", + "nonce": "CE5FAF170ABFEE4B7D446D23", + "section_mic_hmac_key": "A876F7A6153B0A4E0C00E367D2A62C2E69B8B172AACD2F88F5AEA1CE1992BB32", + "section_salt": "ED1132C6CB2146F95306E0095791FB96" + }, + { + "adv_header_byte": "20", + "aes_key": "9CBAD2E4548CBCCD00B6E0FB7FBF9473", + "data_elements": [ + { + "contents": "7A306B5925D15D6B43B7", + "de_type": 149 + }, + { + "contents": "5912AE51A1D62035C323468AF0198079E1A7110FDBA42D", + "de_type": 664 + }, + { + "contents": "091D6CE6C774BDF76F52CF04688503B8496460F3E90D0880", + "de_type": 305 + }, + { + "contents": "248EC62B07E7904634AD309D8238B1514FCEF2D86601BB2ACA027F14", + "de_type": 507 + } + ], + "encoded_section": "026A74D621344D87428CEE5060FFDB570C73D57CE4A2CFF3EB2C14839E619A1D967170CAFCA1BAF48A2E45501A6453450187A1D4854E4B238A56DB9E26F231288701D10E43D8468A1E661AB447C32E366315B6BC1073EE143D7C02458C56030516A3DB91E367C941689CAFD6FA9252FF37B88EE0ED4D99EB9313B7BE72F5931ED45525D49C1E068C96D133078E33B466EECEC2", + "identity_token": "19263E5F61578937D8D7EFC85325267B", + "key_seed": "8578CDF5097D9F1C253B4DDA8471A03AF7F26A01FAE138D2F3D350FBB752FF24", + "nonce": "0C6C9E6B32B490B080285EDB", + "section_mic_hmac_key": "953DBE0C875F66FFFA680AEA984DFF74C906D326B58B19A804F20BD104B236A3", + "section_salt": "6A74D621344D87428CEE5060FFDB570C" + }, + { + "adv_header_byte": "20", + "aes_key": "DCE5AF2A5A7AB0A6F2308EF445084D6A", + "data_elements": [ + { + "contents": "44986ED23F155AC13CB849AD9C4FD3", + "de_type": 520 + }, + { + "contents": "9AE30C51E00E42BB", + "de_type": 294 + }, + { + "contents": "", + "de_type": 192 + } + ], + "encoded_section": "02384716FD70BCC1D2B3572C678ACDCB1CCB3ED7DAD80CEB08CD5C6E324C5BF51830123D1A83775462CC0BD667255BD88D21D8A972AF982CFCCB54DE20E1F38F8A7F6E2E525B13AC0AA5282ECB34FD2AA8C2", + "identity_token": "1831C66E762DD247D3D0A3F7CD278B6D", + "key_seed": "2168D48C66B609FA91D4A98D35F0941AB227F1D05CB42C81E6C3773DBCCE8556", + "nonce": "6BE8AB33FEA8DFCAF84ECC84", + "section_mic_hmac_key": "A62AAB51DDFA839AF5FA651C807D7148269148D0926E1A86D108796B98706601", + "section_salt": "384716FD70BCC1D2B3572C678ACDCB1C" + }, + { + "adv_header_byte": "20", + "aes_key": "A220AB81C5F6D95C89F75244513A865C", + "data_elements": [ + { + "contents": "6045FC019235", + "de_type": 587 + }, + { + "contents": "F46063F443E58DD9A62CF5935E009EB1F4DB4021072AA8662EA3667D", + "de_type": 720 + }, + { + "contents": "335D2813B9BB0B3D302B", + "de_type": 978 + }, + { + "contents": "CBAD44D6954386F14343090074EF8B4BF900F75B810B", + "de_type": 209 + }, + { + "contents": "A5", + "de_type": 818 + } + ], + "encoded_section": "025676256DEEE42A0A9FB667E01DE178058CA5C182B845F41E66D5A78E96C550B1620460461E74C4B4FAA6277A598899798E8E07B73E6B99BBBD4F22767E7B9C751B4AE7FD09529BFC16BFF03E02662E3D2F6AAFB8429B233260311E995B59CB3757479A4F5B1F167E0E461BA882F9F1A95D8B7B5A65014DA76C3796BFAB028974E9F487", + "identity_token": "E98107D0B6209C2F99E458FF9DDA5EDD", + "key_seed": "67397E84E19D943457D649FC1C85177CA2283A285DEC02F77DAE3223822F10C6", + "nonce": "84C350AAA3DBEFE6C4AEE93D", + "section_mic_hmac_key": "CAC3BB4657D8FE9840CE0B2339AE0F7416D583748B89D950BDE6DECA04EC5C5C", + "section_salt": "5676256DEEE42A0A9FB667E01DE17805" + }, + { + "adv_header_byte": "20", + "aes_key": "8183EC3E35044B898637AC452F1344F8", + "data_elements": [], + "encoded_section": "026167137CA22AF2130EA98F1046B4063D4D2353C7595F0631AC75DC9B450BEFEA106A6C243686C795EE3D7B68717556E523", + "identity_token": "E0855E9D123AD57CD4BAA1619A33CB8F", + "key_seed": "1572B2064990B9BA7EA8FD487BE6580BED3AD5332CA54605D801D82C25813372", + "nonce": "1AFDA6FFD7B3CF5FC5C2844E", + "section_mic_hmac_key": "E6F8DF148FC91C004791D9CB5E6881CA536E14CB366F6B2D73C1C3995161A74D", + "section_salt": "6167137CA22AF2130EA98F1046B4063D" + }, + { + "adv_header_byte": "20", + "aes_key": "083CFF217DC4F7DFFA8B3989A602A800", + "data_elements": [ + { + "contents": "F01E2E1B19F7F410819FD81F2B22F7065E3164E1A54ACFF05B73D011", + "de_type": 886 + }, + { + "contents": "87A24D8B5990862B291D9CDF44A7CF15", + "de_type": 363 + }, + { + "contents": "", + "de_type": 230 + } + ], + "encoded_section": "026DC137DC284DA96BE876644C985CFB021DFDAB61844B115F94E05FA2D4EAD52345AA96C988FB3376D05D29BDA4D027AAFE41CF5E10625A61B12A000FCA96AD5D5BAE78AA3A8C186DCF5729744F572FF4370291D35642D5088995AD034E28CC61D05876729AB1", + "identity_token": "7310CA7BB155529509A89AC74042075E", + "key_seed": "5DC834BD1930C71E749AEEE8E3518EBC09C9B860B6F6372D58A1BD141E89B08F", + "nonce": "4410414C0013373CBE93D03E", + "section_mic_hmac_key": "B9B9B858E9859BA09D8A1F17B0E6AC0C5F6286C708C95552A464924B629C7C10", + "section_salt": "6DC137DC284DA96BE876644C985CFB02" + }, + { + "adv_header_byte": "20", + "aes_key": "B44C62C6931281637F75DE6F1D3F39B1", + "data_elements": [], + "encoded_section": "02048517CD42EC7AF6C9FB66E2F3078ACFA38819E6A4E0B9BD8859750BADB4232910C0BE5A04C215798BC885D7781C579B72", + "identity_token": "D9EB6B7007B30C0EF6CF01A7910D8B11", + "key_seed": "15F39B4B7DA56E28820DE711A002EFE525A5E32605234508F57E31A12C520938", + "nonce": "EEABEA7D9A551E134F3BB00E", + "section_mic_hmac_key": "0C9AFE67BD257E145EDC49C851378382C4899F18B61ED1A9D1488D63D9A7AE1B", + "section_salt": "048517CD42EC7AF6C9FB66E2F3078ACF" + }, + { + "adv_header_byte": "20", + "aes_key": "187638BAC5FEA85287840A933BF6BC8F", + "data_elements": [ + { + "contents": "15CAF364A09A674E23B3724F87", + "de_type": 655 + }, + { + "contents": "B44AAA22887D6901DAB2B15D2821DA6CAF", + "de_type": 663 + }, + { + "contents": "3D75D65255A28AFA0FFAC86128AC", + "de_type": 568 + }, + { + "contents": "8F87B0032134C16C3A5C55E944216C6CBA1FCA9699", + "de_type": 919 + } + ], + "encoded_section": "021131C64A1BDAC5CD00E80724986AB4FFD8B57A83029720FCBDD1CB945FA6A0E95D43C3FEC6573FC13757D4EDF3D85AD806A456778D52E013B1B418BE71E73CC08857EEF334BC2DBC1AE87C04D8D5FC35874B09964455EF5B444D0569F53D2EA3F442011BB799A6646E266EEDB93BB2295E58C17BCE62C63DF2A988773A94", + "identity_token": "33C178C3119530767A131BA20E39C282", + "key_seed": "B1D18E5E497268A55170AE018FE33B3085490E7FA03A04AF02A6853BAA9C700F", + "nonce": "19A21AE5D8370686F9D64523", + "section_mic_hmac_key": "F751860DCF60C03436AA4782865E8C89C33C1851352793CE41E3E08B5585866F", + "section_salt": "1131C64A1BDAC5CD00E80724986AB4FF" + }, + { + "adv_header_byte": "20", + "aes_key": "BA6A05D814D7478B1D442A0C6E5ACBD3", + "data_elements": [ + { + "contents": "7E5AF9A1D0129006", + "de_type": 272 + } + ], + "encoded_section": "0284E383F03BCFBA802956AC1D331D49148DBDAE82CC80EF8E854495252475C3491BC6A881642FDDA6C4B8403F32D4E3EBC65F5702BA53D740EA6A01C2", + "identity_token": "2AD4A3ED2DB4D967EAC7F080F4CF40C8", + "key_seed": "19F9E4A47586993C7A276A929D00A0FFC15FE2F4020CF6B05B04C4F4D0C6DD1A", + "nonce": "F807F49730187CB3ADE6199D", + "section_mic_hmac_key": "1576D69950F0F1E079F379F3ADB914775C4AD5AD22CD61561F8B9372225E8019", + "section_salt": "84E383F03BCFBA802956AC1D331D4914" + }, + { + "adv_header_byte": "20", + "aes_key": "EB5575D5CF3527ECA045F3979A56A309", + "data_elements": [ + { + "contents": "35D7835CAC", + "de_type": 205 + }, + { + "contents": "7FE4C599A437353892D3C213AC6A1AC604F4F9AF", + "de_type": 582 + } + ], + "encoded_section": "02ED47A961048AF2432C532A68C85D8774E661489D120680C88F13AAEEBB7FB3492F43D8628F8F4F0908A22FFA780DDD956F89A5050DBB98E4F52C25FF30349A76D9B9E39D7FEABA2E63CBAA742B683B65", + "identity_token": "82A145333F4DEE9F069AADF41C54F072", + "key_seed": "DE758EEEE4750E04730AA94B4F238B6CD535F551C2BA67446A254314D600ED28", + "nonce": "4241309102A36EEB9CECAD67", + "section_mic_hmac_key": "4C1043B09127BBD4807B84CB8095EB362229FD36D9392553B988807B8EA386D0", + "section_salt": "ED47A961048AF2432C532A68C85D8774" + }, + { + "adv_header_byte": "20", + "aes_key": "9BD48ADA5F488E055CC936AE39807325", + "data_elements": [ + { + "contents": "342C2F6E6DC0F507E670A49386", + "de_type": 389 + } + ], + "encoded_section": "0288E7C4BD0D3B41077F9D17F9CDFAD09AC4BB564892C8E1CAFC76393E1BCBFF0720893D1D78C7F60C4A4379DA5631EB6410BBF5B9D2E695C95895F1386B3533A72F", + "identity_token": "98AC76B171BBA2D6F74D2EB070CCB2A5", + "key_seed": "289A2476986D21D1D4461D43370BFB00BAA75DB8129366D1B287E1DF2346D686", + "nonce": "5AA5D7324173A3A8B25CFD2E", + "section_mic_hmac_key": "613B7BEC61CA3F4917327E9F57265497A2DA3FB4A8D1A2E64F450E70BF4C2A55", + "section_salt": "88E7C4BD0D3B41077F9D17F9CDFAD09A" + }, + { + "adv_header_byte": "20", + "aes_key": "D6964D2F633FDF7ED603E51BDDC2257E", + "data_elements": [ + { + "contents": "AC844B564093FA92B8CA12B19613D2F77F4A656F8319", + "de_type": 600 + } + ], + "encoded_section": "025588191AB27D12C53FBB0AC6514C35B6A213087FD19806FD6344B4BB336E49962992FB90F69A43E3D3281CC6E20822037F382FB9D98F25653F9FA6984E51DEBAEA3061605A4614434689", + "identity_token": "A0A4A57454A31A1B4CE36D757ECD18AA", + "key_seed": "AB60BD9D7B2DBE281E8A6EB916B2042923046CF68F36CDA67F27E117AD4A7CC2", + "nonce": "82E43E99AD73B19CFD430B95", + "section_mic_hmac_key": "8F4D7D6A549F07659A3FC656056C17916AD3A4ADAC5DA504388BFEF875990157", + "section_salt": "5588191AB27D12C53FBB0AC6514C35B6" + }, + { + "adv_header_byte": "20", + "aes_key": "4B9221D8B63D26A9711B130E1C0535EE", + "data_elements": [ + { + "contents": "ED6EBC", + "de_type": 591 + }, + { + "contents": "1D8DDBD8DF0C950711662DA284BC23FA6C6FDF479636", + "de_type": 29 + }, + { + "contents": "7AD06A9E86A0A2DF", + "de_type": 596 + } + ], + "encoded_section": "027EF3DDC32AD8B67DEB708CB96FACF7E87C2ED0A5F105F30E74CC01BA5995023B39908CD7C3A28D416AD43B60A822D3A6781CEA5EAD3A26EEE188FEDBCC4B86207D626E3A7C5177E7EBB46D720404463C45A0832B3B146BF9E842", + "identity_token": "46470C0BA32542A5ED33D66AE1481EE6", + "key_seed": "7397B457C7BACC338D5C6134346FAF2D3164EE0E53FB48C18EAB31257483E83C", + "nonce": "BF76260300391F69E456FE0F", + "section_mic_hmac_key": "7056AD67950509C88DFEECEBE92D739F5C702C566F1854EE785EAC1509C26815", + "section_salt": "7EF3DDC32AD8B67DEB708CB96FACF7E8" + }, + { + "adv_header_byte": "20", + "aes_key": "1E806EFC9EDD141577721BB5E61CA53F", + "data_elements": [ + { + "contents": "57A7035EA380C98F071876E21F4CEAEA67E964A732568F5D10AF", + "de_type": 518 + }, + { + "contents": "913B76C6EA7BE3C1FAF1C2E1CD4F929F4F56565BCC1113674C17", + "de_type": 898 + }, + { + "contents": "", + "de_type": 415 + }, + { + "contents": "5D48E33377BFA3527720447FDC7F8DA97DFC44DC4A", + "de_type": 588 + }, + { + "contents": "A3", + "de_type": 908 + } + ], + "encoded_section": "026567A1F3D63165D9D7A854C9642CE61B9DE8B6E101BE92EC9ED692E04BF86E866946345059A1F4F9C54A625AC3EC77B55C37C774CD11AF71385AFB813F8DFECDB95CA83929CB8309AE5206F125E22E25368DA9580EAAA50F61EAAF37FA6A61D44CA946D3BE28D9E298858E09DF3D50CEF793CA14D94A733C1FE663A8ED047D4718336108C1154EBCE52E", + "identity_token": "DE24F284089324DCB3AF76801C2F94B6", + "key_seed": "6555B34DD6A332E6F727381BCE1A2B9FBDEC1B5367367BBCFCB5071BCF8178DF", + "nonce": "F423CF36EF58853645712DF1", + "section_mic_hmac_key": "54C323CCC04E240721D7F77C1205F216D251C79E41FCB3695EAB28C6C5423C40", + "section_salt": "6567A1F3D63165D9D7A854C9642CE61B" + }, + { + "adv_header_byte": "20", + "aes_key": "77F61511E7F92A37D2A114DD4CC4889F", + "data_elements": [ + { + "contents": "51F97F", + "de_type": 22 + }, + { + "contents": "EB58DF0C96A41AA69329CC97D11242F4A3850D89FA82376C83", + "de_type": 110 + }, + { + "contents": "BDFDCF83C918D94DDE25E6A13E0586CD83EFC76F5C43AE46CFFE", + "de_type": 674 + }, + { + "contents": "F2C0052877838299", + "de_type": 273 + } + ], + "encoded_section": "0282028A9CDE5CFB8B7B85C55034433DD7A9C6DC3CEEC3F54854F91708D8DAD5B458C396ADD9D43DF02B09513E3E428A0B91BC838C3D10B5D755ACFF0BA217A77117A96C3E2D5849F2861E7DC257A3450D740424901564F7F25EA0E7E239E628C8E22381D9B0FA86896E0A562DDCB26E1E6C4EB2DB7D4559CEA1", + "identity_token": "15A7903360B4430A13965FC72FA2B9D2", + "key_seed": "E06BFE99B917D1C1B38AB13D3F6A2163AF91507531E86E5F6F32D7116D94AA03", + "nonce": "F1728A657AD70C28875CBC1E", + "section_mic_hmac_key": "3AEAC66D3852FEB86D7D1FCBEA0A9D6EA47EFE74BF6F2CB6E861BB1ABE8E3657", + "section_salt": "82028A9CDE5CFB8B7B85C55034433DD7" + }, + { + "adv_header_byte": "20", + "aes_key": "C606686684F622AEC70CAA4F201F2EF3", + "data_elements": [ + { + "contents": "4FA0D0", + "de_type": 599 + }, + { + "contents": "B3E804B287672E412D53B1183CEC5D", + "de_type": 174 + }, + { + "contents": "526BD3460157EBE8D364D73C30419689F8E5EA4A47", + "de_type": 461 + }, + { + "contents": "C378C50F", + "de_type": 800 + } + ], + "encoded_section": "0222C5A6BC119ACEB0EC9EDCA6D57639B767DE04C14B5F0B4DEE8B49E4DE3AC7CD47CDEFFB4ECFDF012DED1CB340D2E3D98D7DE9970BB9F48ADC6998B8A52B1CC674048CB3C58752BAFD16B73DC21D36973DF5F18BA6027AD6060AB0EB78862BA8D7BED26968C3629F", + "identity_token": "59BA27AA8A76A50F12A5D2BC8EDA7635", + "key_seed": "CC49C0BC358FFB2BF90A62F446709CA6A6FD1CE686EB7D4EB37FF620AB5866E1", + "nonce": "D222455382EF2556A27EF3B3", + "section_mic_hmac_key": "507CDE4A24AAAD3B43BE6AAAAE73CA5C5F59D011AD220F1272E7FF4D43747F22", + "section_salt": "22C5A6BC119ACEB0EC9EDCA6D57639B7" + }, + { + "adv_header_byte": "20", + "aes_key": "A33086631E13B0A0226E32EF4D4CCDBD", + "data_elements": [], + "encoded_section": "0228770D81B47DD0E4F188546B893534900F41411BF870D5E9458D457698D1F74710D4A0F4340600E0E9285E5E6F3351E3CA", + "identity_token": "92A3CA4B2F9F59AB64EFBBFE25121C7E", + "key_seed": "D6AB21137556AF94989CF92E53261B867163C16147313EC5275B8E1DD5073BE1", + "nonce": "59480DC604E5C6AA30BFEF23", + "section_mic_hmac_key": "9B12B9904F7ACF8E22828B994212CABE3FC8B85F6121D1E5D47951473A0379DD", + "section_salt": "28770D81B47DD0E4F188546B89353490" + }, + { + "adv_header_byte": "20", + "aes_key": "05099C0809FFCE0781D65DB0E2F6B265", + "data_elements": [ + { + "contents": "3B", + "de_type": 789 + }, + { + "contents": "2626C80C748B72F0A32FC66788960604A3FAED3070AB9114B8E358106CBC", + "de_type": 671 + }, + { + "contents": "09F36841", + "de_type": 406 + }, + { + "contents": "", + "de_type": 145 + }, + { + "contents": "BCBA4F2899DE", + "de_type": 446 + } + ], + "encoded_section": "0227A3A0FE2CD4B612A4DD0355C51E1C2D53FA09EAB78824316A73D15FC3238396482A461EEBF605D7B33293B3D196BF25B1667EA66BB514A7F7EF27648FB8048B94FA70B2D4EA36BCD86D913ACA072E6D89CF3F5490550820D362E1A8B395B539B466D74A9592AA8ECE", + "identity_token": "C76668A2A2FA840BC9C89353B8540B43", + "key_seed": "162E48714870CDB8C0BE54F698A9010FFBC9532C15C8C2DD130D579AB4AE4512", + "nonce": "08860371E5C35E5F8B076FB5", + "section_mic_hmac_key": "DF7611BF559EA9C2D8A0A5E7032D4813971952E0A8701C4F55652939CA1A47BF", + "section_salt": "27A3A0FE2CD4B612A4DD0355C51E1C2D" + }, + { + "adv_header_byte": "20", + "aes_key": "B5B046CFE2E170E4E29529FC53380945", + "data_elements": [], + "encoded_section": "0209539A273A8888A0158CB6D08FE4CC1C0839E0605B3EAC31AC2855629A66D6F2106532ECC714BF797E4A08D85E49AE31DC", + "identity_token": "A9BF53E9D87F9E63328C211778CEB74B", + "key_seed": "AEF3279A8EEC857AB241D4B6678BAC2CC4EAA9CABF2A4C229E9FE17C44D725E8", + "nonce": "025E4CF04B1E5B5A77BFCA51", + "section_mic_hmac_key": "967C2FBC5F186228F868E5BEA0482273B1686A3411687FE6123FA533BB4D7FC4", + "section_salt": "09539A273A8888A0158CB6D08FE4CC1C" + }, + { + "adv_header_byte": "20", + "aes_key": "5126EA9102AD6B5ED537A4D06C62A735", + "data_elements": [], + "encoded_section": "02FA35178CEF220907A4C1C1EF1AB507C7D294D3B20708B7D18524BF185DA511A510052AA4B0C8474901B9B7E8D7B64AC9E7", + "identity_token": "027C381EF363ED32EA4CECA28DAD7FA8", + "key_seed": "6C43637A9F73217C7EC4D4754A0B292230B96368E7D4A70FD3C42B3F42E11685", + "nonce": "3A6CD0CDD1DF482C7A7B44D7", + "section_mic_hmac_key": "E2F8A00B2F7AC93D7BA123A5855124052A4077FE7CC331DB260AB2D284A87E1A", + "section_salt": "FA35178CEF220907A4C1C1EF1AB507C7" + }, + { + "adv_header_byte": "20", + "aes_key": "6451E8C836D286C2C658118FF5E0F808", + "data_elements": [ + { + "contents": "7E07F945516A13D0910FBBB4C05258A4B21405268DF1DD3DA8EF", + "de_type": 175 + }, + { + "contents": "86D01ACD89762B2F", + "de_type": 691 + }, + { + "contents": "A0151F3798A7E3E871", + "de_type": 81 + } + ], + "encoded_section": "0278DBC03386503100B99EEDFDAA3A54AA59606C74808EA12DF14116C0AAF2551143D8F46AFA3CDFE853CDB017AAA6AFDACBD1B5FD0088A709C4B9F007DD53269BBF736DFF095E0C7AD6087B9B8947B5F6D22C5ABC75278BAF2ABDD8D326B3D07C96C370F1", + "identity_token": "5A1729E7B2B2193C67112CD8DEC59637", + "key_seed": "82158E1C98CAE04C9FF662087015A804F181B25565FC29BB0CCEB32AD29AF8A6", + "nonce": "1C4B30EFE7A7EE25837487DD", + "section_mic_hmac_key": "3A3FEBA1F8EC810C8ADA1EB14859C5CC3B1A391B0ABEF72BAB65DC1EF1AD7E43", + "section_salt": "78DBC03386503100B99EEDFDAA3A54AA" + }, + { + "adv_header_byte": "20", + "aes_key": "37CED522A58075CD5910D4AD5C755AFF", + "data_elements": [], + "encoded_section": "029134AAA791A8F2F363752DE40D98CAD079A38F6AA2E33B1F368213CA503B1EBF108276BDB43AEFB7AF93C1B94EBC08EAF1", + "identity_token": "542BC2A7B465A7069300EA500112834B", + "key_seed": "B6DE0DBCA9A2C1290749B479AEBFF54549CC733CA19439E66A8EC38A81AEEFA1", + "nonce": "D8FB3E5CBEECB405135DE22B", + "section_mic_hmac_key": "311EE9A96B22421A80A8813DBD29ED80FE7AC3212A64988033105047A72A90E6", + "section_salt": "9134AAA791A8F2F363752DE40D98CAD0" + }, + { + "adv_header_byte": "20", + "aes_key": "D03161023435EBFCAF2F2D0ADAE25EFC", + "data_elements": [ + { + "contents": "28", + "de_type": 471 + }, + { + "contents": "6536FA2872CDAF623C96BCEFF2471CB4E036039A4BE890ACB57FB1EA68", + "de_type": 72 + }, + { + "contents": "3F9D7E766C0879AE49D791", + "de_type": 118 + }, + { + "contents": "1D4CDFC938C8BE1CEE8BC23DA0D65E51121C1CE238E37259EE389D12", + "de_type": 778 + } + ], + "encoded_section": "02A17062B53D66D4533A53A453F2485BE62F35088593326E7742857102AD4D29E45FD71D6D2423810C4B94EE6C28BCB8D171D49564294B141921978D180CA20F1798397775BF0E1F4182C915E186E768837E8E7779611BF91FD12C2E9E8608BE33C4AA6E7664C477D7186E03151F5692C1D61E246BE67263333765EF7573769AAF", + "identity_token": "DBB90C1A48327EF7A00F4B43D68A1F81", + "key_seed": "92750637170C948A4C8F8DBEC0C99DFA3B3F62D666E78860A0E66090E9EEAF46", + "nonce": "90059268A0BAAB4B5C27102D", + "section_mic_hmac_key": "D894D0DBC6434DC2E305B9DBAE11164339617951C9503578183E2243A89A0A62", + "section_salt": "A17062B53D66D4533A53A453F2485BE6" + }, + { + "adv_header_byte": "20", + "aes_key": "4709FE87DD6401199C69B10B42568335", + "data_elements": [ + { + "contents": "1C2BBEA2EB6A22D4", + "de_type": 213 + }, + { + "contents": "5734FB78B9DB664F434594B0DE", + "de_type": 745 + } + ], + "encoded_section": "02C9525C2999AA4C2313D3A88E0DD65385C468B7D341E9C2DA03D43E31514EAE512BB2AD526CF2AE44A758B4DEF16471C615F34A79E7CB8E4294BD91EA791BDA401DD3F4A6BA80EF87187D037E", + "identity_token": "67B6209E52C3003631906D5B6F8F99E2", + "key_seed": "E8BBEFAA58A804851A6A5FEEF442A5B42E1790D624E171D82666F37D98F479AD", + "nonce": "13ACC6C2DEB7C80286605695", + "section_mic_hmac_key": "2C5777BA0FC851E2168A7F6A065542A454A00FDBC37796DD2C0F61B8F0F479DB", + "section_salt": "C9525C2999AA4C2313D3A88E0DD65385" + }, + { + "adv_header_byte": "20", + "aes_key": "50D0D6451249827DFEC86AD5CABA7541", + "data_elements": [ + { + "contents": "A2365C5B", + "de_type": 232 + } + ], + "encoded_section": "02CCC6C1F682DC2B26C2F0EBD88DF8CD10B46827F6998B5BCD033810162169C9E6177E21F144FBF887F2D62C9384E5C67E9C293E808D79710B", + "identity_token": "84A064CB500C36450216D83A3893987A", + "key_seed": "BD2E624D9CFE4D8BFFD5F64E71D91E7E6C355207AAC713DCD27E762E43F93778", + "nonce": "2CD2585EC8A6FFB46BDD67B7", + "section_mic_hmac_key": "CBA836A7141228C2F80DD3CBA933639E4901D26EA5D596DF73749070389E72FE", + "section_salt": "CCC6C1F682DC2B26C2F0EBD88DF8CD10" + }, + { + "adv_header_byte": "20", + "aes_key": "353C59AD9C7303309F3F25D3DA7D5623", + "data_elements": [ + { + "contents": "8E8E775CF15104DA9C2F070D9778", + "de_type": 22 + }, + { + "contents": "C05C83A5", + "de_type": 492 + } + ], + "encoded_section": "02E13EE1C144ACAAC46546A7FC73BC517AEC2793AF4C8289C1179DB702134B875F279099ADA5B9F9D20CF79506163A1BB5B7CB158AB8FEB2D5BED7A9DC2737819FB7B5DC2475404D58", + "identity_token": "8206FA4E58FBB7DB6CCDC6A8E17D215A", + "key_seed": "9BBCA7052AAB7FFE1E37DCE21853BDC901CA146141C567A77E042D1DB8E7677C", + "nonce": "60FE311C1DE98B1F0CB8F645", + "section_mic_hmac_key": "9AF2DB9C6C964A6B120625992CBFE9810428FB44F41EA85EE8C98FAF048B45C3", + "section_salt": "E13EE1C144ACAAC46546A7FC73BC517A" + }, + { + "adv_header_byte": "20", + "aes_key": "63DBF59EA2D3FAD77153DB5412A0468B", + "data_elements": [ + { + "contents": "4657BDF649917C3279B8D5E6D8107DF5FE", + "de_type": 698 + } + ], + "encoded_section": "025368A3DEB0ABAFA3684502DBF3F2D2F1A4919DA6DFA241CA937D946397B2FAD624E77A62AC2FC3FFEACDED692D3C146025FD5E9A540D93A6BB85443C5958087A248897A165", + "identity_token": "2F46468244F32581D94A0E134A269C27", + "key_seed": "8C34898BE3791991680388FDAE3F11539734BD838C00F4D721D886031B1CD8D1", + "nonce": "158DA837D312152F80C64662", + "section_mic_hmac_key": "62BCFEF7FABECF3EF0B822A4970BF3444DB880A02805943EB055FE7E3E5BBFF7", + "section_salt": "5368A3DEB0ABAFA3684502DBF3F2D2F1" + }, + { + "adv_header_byte": "20", + "aes_key": "6FF3996ADE933F9445D5D9B3BA72ECED", + "data_elements": [], + "encoded_section": "02DFD2A8ACFCB1979E11868B2EB2A148861E7D3C74802325EA20998C2CF3013BA51070A82DE70003EBD48675EFDA6C8A1040", + "identity_token": "573B7D3AF2FD3EDDDA487D8254537EAC", + "key_seed": "45B309037CCE98B8DADF3DF7818D3A3B842E292E9F8C54E82F10C4B91EE601DA", + "nonce": "9FFEC13ECBB99430B280A426", + "section_mic_hmac_key": "4C699D0E312750AA09EFCA9A4C8C4E7E032BC4D5398A6F72F4FB6AFD22D64110", + "section_salt": "DFD2A8ACFCB1979E11868B2EB2A14886" + }, + { + "adv_header_byte": "20", + "aes_key": "95D640F8FEEF0F476D173FB35C70E3A8", + "data_elements": [ + { + "contents": "0E32AADB46", + "de_type": 405 + }, + { + "contents": "DD700C351B", + "de_type": 316 + }, + { + "contents": "C58F70E4A3F3EDBD5E8E2F0A", + "de_type": 651 + } + ], + "encoded_section": "029855CCB82C1B5CB8DBD66839B011C07894F5F607E6B8C7FE9C8841A25BB06AD92F451F1DAD781A11061A62ADB2B7F8E951759290C76BCF3497C6323C597BFDB3DB01BDE012660251994A30CEB69F3E76", + "identity_token": "4D475A274742151475B341C48194D9F5", + "key_seed": "4DCF489FA193E73A86A4EB4C3268CEE5B950A1957C0CA006F3422A15A11DD205", + "nonce": "1BC76946373179415F596851", + "section_mic_hmac_key": "3381BD66395B21BCFD1C73E775C967784C3F3DE77F2FC1EBE5D2CF5EEACB91C3", + "section_salt": "9855CCB82C1B5CB8DBD66839B011C078" + }, + { + "adv_header_byte": "20", + "aes_key": "31B7CC1805DAD1ED55DFCBA3ABD6C01A", + "data_elements": [ + { + "contents": "D5D8A14C3B06", + "de_type": 534 + }, + { + "contents": "4D974CBC01B6728564EB30C3C780500EC117E0B2667EC576E10D7DF5", + "de_type": 364 + }, + { + "contents": "79CC9D9954D0C77577859D94D862FA", + "de_type": 131 + }, + { + "contents": "F1A1CA7D01BCF394", + "de_type": 115 + } + ], + "encoded_section": "0220E344A3BD5D875DA30DF57C04B32022F56AE8CF9A5F02F774BD2483829674CA544027FC5D3CDE71FD19D2AE4861CB74ADE4484C3F758870EB49C211D07B2A0B1DBCAB684203713EC5ADC830B6FB75C927813EFC51BAFED6ECDF8322B679FB9190DAD7AA7915BDE58E399FE58066EBAB338B8F1AE1", + "identity_token": "4AC470B5857B8F029D2F8E4B634765F2", + "key_seed": "41F01CFE759E12F979BB0A6B23DBF53D408761D4F667CAB71042C9789588CC44", + "nonce": "8BACC88ED412BB6E927D153B", + "section_mic_hmac_key": "E7B1D619DF9082D0A9328111D0D72FD515B276BA4954B697B942363DBD12120D", + "section_salt": "20E344A3BD5D875DA30DF57C04B32022" + }, + { + "adv_header_byte": "20", + "aes_key": "D75007BB49FEF17E0CF767B19412BA83", + "data_elements": [ + { + "contents": "483FF7B534C3DC8427", + "de_type": 702 + }, + { + "contents": "", + "de_type": 310 + }, + { + "contents": "02826430E4AD154BAD4FC491CFFEC8", + "de_type": 638 + } + ], + "encoded_section": "026B334E9E52C272A60F1CD9AB613752273F973DF5218C53E2B5FC7487309A978F31870C486D424DF9B79D0D68C6594ACC1E30F8F4D7F3FC7E559FDBEFF1B88A849FB996E466D2F725D8C76BFC705F34227E67", + "identity_token": "60040508990303A048FACF72038CE464", + "key_seed": "98DF428BC184564FB1DCA947106B8F89CBB668C74A9CB48C0721430BD2047A1A", + "nonce": "C4CC65DCE3FA0CC241D9AA35", + "section_mic_hmac_key": "49AB3D69719CCE05B5A246DCF61AAB29376178213347CA7F318F9661A21CC63E", + "section_salt": "6B334E9E52C272A60F1CD9AB61375227" + }, + { + "adv_header_byte": "20", + "aes_key": "FAA4F8C869F0F4469CFA8B98E0B84786", + "data_elements": [ + { + "contents": "9C3CFD4796001FFA0F0B1A17C2DDD4971945CF1581", + "de_type": 900 + } + ], + "encoded_section": "027EA134E36AA6249D20357948A07A39430106C70B56C2DDD6649EA769968F03AE283A99A8441AC04033B08878A90E7684242045AC3A191170C5ACBB55B2218679CF770A384C7FB67E06", + "identity_token": "7FCFA0BC8F7C8C85EF59ADB9D250F8F5", + "key_seed": "7032B5E67A8BEF82845ADF25B6152283D544435CDCABFCA0750BCB81A84934A8", + "nonce": "018137DF8171014B5AA4F794", + "section_mic_hmac_key": "F2571523E2DC1E97A4A1D95D74967F22268C47733385C3241FAB1653A1F61BCA", + "section_salt": "7EA134E36AA6249D20357948A07A3943" + }, + { + "adv_header_byte": "20", + "aes_key": "135CFF48972D3892BD5236733CBDE72F", + "data_elements": [ + { + "contents": "13E83591B1805E6EF828EBAB8189A0F7F47E65F6EA9B8EDD", + "de_type": 325 + }, + { + "contents": "8582F902174439B061C45305", + "de_type": 514 + }, + { + "contents": "ADF4960FABA6559565B659F87C13DD9C0838CCF7881CDC", + "de_type": 133 + }, + { + "contents": "F4884DC85E0B24372426BC917E7824B9CCC6C682619428170A2EF989CF", + "de_type": 863 + } + ], + "encoded_section": "029EE7BC1BBBE9DABEF0A56E7E11D1A11D432AFF55DAB52B42407E950ECD6FB8D174564E551C9E68F5C5F229808F63E587225B49D682D481A708DBDCF8DC53D55AEB7250AF51464C4C8EDF689933DD8414BAD3BFA8C633B7914A67A55D90598A8070EC256500F60B92F22B2E0A08749AD01AD7AAFEEC9C547993E7D8F5495E1D9B0CA185F41DAE0F48E4E953530CF8A8EF77A80CDC11", + "identity_token": "24DB26605841C2C1F2FF4EAFA8C9A3B6", + "key_seed": "B80CEE8A5289B0E88AEE0FD08789C7D762F4DFF8D0FC5D79CC9332F24F7AB889", + "nonce": "20979F413869AE8D0069CEA6", + "section_mic_hmac_key": "F57425B28C88DD3C938D7C7F9E2E2DEDE7883C21116B6C2AECD9659F508172EB", + "section_salt": "9EE7BC1BBBE9DABEF0A56E7E11D1A11D" + }, + { + "adv_header_byte": "20", + "aes_key": "DDC14ABAE3E57A2E436D2B154CA341E2", + "data_elements": [ + { + "contents": "0100CA9F13A748A7769E5DD2239A", + "de_type": 465 + } + ], + "encoded_section": "02AD0144308355660F11BC1522BB4040343B6EE18AFFEF9B71D3239005448AD9FA2193AA48A6A9D558FCC66E02BD74A9A83891166A550882FDB1654D80C853A5F40E40", + "identity_token": "70AE495464B5C777F3B7533287CABFA0", + "key_seed": "703D9283FAFFA27816DFE81AB6FC0C86F70F9EE2A59F9AE9FA675BB94F4AFAF2", + "nonce": "F29395253E56ED38E3AEE6C7", + "section_mic_hmac_key": "62107DA82458F0FF6C1F510024186527BEC70BEB8E9E2BC63618656F1F10E27E", + "section_salt": "AD0144308355660F11BC1522BB404034" + }, + { + "adv_header_byte": "20", + "aes_key": "744AC27B83E2766619EC0FA0A3B7145F", + "data_elements": [ + { + "contents": "8809E7D36FF481A81F7CFD46325C0E4999977FF41E8D9E6D", + "de_type": 326 + }, + { + "contents": "662C4AAB4A9065207E", + "de_type": 794 + }, + { + "contents": "7B302C10AB20F7E646A1DF783ABFDD4A568C9C1C17E26F8A", + "de_type": 111 + } + ], + "encoded_section": "02CB4B333C50936FA751BFD0BF7F69C50DFC0358422A96FC26DC3450BAF84BB28751B73C86769524A89061A0178DAF1B8BA70B97DA597B7B4536312CD3FE3302EEC5659948F0310B6A04EA623628523BA417256D89531912AB7E5F5DF54EF46DD764CF9B7E10303A4CD3CE36A96E5F46139A98", + "identity_token": "A8ED77B3381D625297D75804FE02F5F1", + "key_seed": "94DA586A9221F4376146845409E3CD6C6464BD5313D34E2E6AAC864BE7088C20", + "nonce": "54278CC24894F36FD3FA5AF6", + "section_mic_hmac_key": "FACFF42071ECFC827096DCC9464F0FD7EE42772DE4D3CB9E33AE208A206D8145", + "section_salt": "CB4B333C50936FA751BFD0BF7F69C50D" + }, + { + "adv_header_byte": "20", + "aes_key": "8382239DC9F8AD351C6691B8765751A8", + "data_elements": [ + { + "contents": "731A9182CFCDCB4B5AFDC795BB7D773039", + "de_type": 672 + }, + { + "contents": "AB559ED81984D1E11D3D77C65B1B068E", + "de_type": 34 + }, + { + "contents": "EC20C11534", + "de_type": 182 + } + ], + "encoded_section": "02574DD074E3030F3C440118AF057A6E81DE77D7C6A81CB708D46329C685DBF63A3E49CB49CE48208A0BC9BE897C615383859784266BEABD8739CFCEB412B7D160A078FC7DC9717CD450C0EC5CFE6FF9078EE887CF798B061A8DC8A0A4B81FA7", + "identity_token": "A23C1EC6DA331C8BFCC59AD45299A8AD", + "key_seed": "3FFFE6BC8E09AEC10917636F693B7B623B83B0F60CD0A53B6E671AFA06BA71D7", + "nonce": "603365E941059E1DBA63216A", + "section_mic_hmac_key": "0600965BADD5FE7A27707EC8DD96E50F8565A262FA2F006E9C34C32FAA442F21", + "section_salt": "574DD074E3030F3C440118AF057A6E81" + }, + { + "adv_header_byte": "20", + "aes_key": "0B146273164E3535D882394B7D8E8A10", + "data_elements": [ + { + "contents": "A6", + "de_type": 435 + }, + { + "contents": "FCD83E31FC", + "de_type": 117 + } + ], + "encoded_section": "02DFD3246C71A4A97E4B1BA9D4F7AC34AACDAA84C85C205A6730B0C34D1925BB3D1BED7A91D44420270CFAD5FF0D68D5A081A74B5E6A9F825DAA528DD0", + "identity_token": "F188D1E3D8D9C0272F29936D3AA2C4C0", + "key_seed": "0454EA82B20D1CB3895AA549F07794CE16A417EBEA2D45CC3D7CEE88840D1DEE", + "nonce": "4A37E74B7919321224347C0F", + "section_mic_hmac_key": "89FB1E3BB8673A6A39207460CC3EFB7BFEA89A274547F2C1DCD105AF454A48F7", + "section_salt": "DFD3246C71A4A97E4B1BA9D4F7AC34AA" + }, + { + "adv_header_byte": "20", + "aes_key": "A6C5055276D8481CEF2ECCCD19DC6D86", + "data_elements": [ + { + "contents": "E8C34AE045BECA84AFDF145AB2C11534C16FB5", + "de_type": 260 + }, + { + "contents": "87E8D027D88BDD326D08D4B0", + "de_type": 547 + }, + { + "contents": "A74A12CFF895DE4FD969A2BFEE920D3A131220", + "de_type": 954 + }, + { + "contents": "C02CB796EE5010050633D340C8", + "de_type": 784 + }, + { + "contents": "32EF1931690553C3B4AEDD035D12FB776F93BF91", + "de_type": 742 + } + ], + "encoded_section": "02A0318DC4C04450120D114911CB0F21DA6895C9D7D2B7AF43E57F6DF8A5B85F297250D4B38EE384132B5026A691A5A848C1284550348231A6A97CF8D47CA5F1F71AC81B984264A05F794327D9C50A9F72A5A102CD566D023DFF1C4E116C82B83BBC8A0884611E37C6CD8581360318DE18DC880E2B00048F9C4308A81975B0B73F0A255F229D267F19CEDE7329D8180F71978672", + "identity_token": "E0D703959CE67BF41B6976FD455FCE5B", + "key_seed": "CB83F57DBD5CE9CA5F898CB4F5556A090479FD88C20F7EE18D632FAF178323A4", + "nonce": "380124B5FF2BF739EE781770", + "section_mic_hmac_key": "B044296E5AD11AE978E19E56856D6829769C3F38E488A3D741E9AA632BB32FF7", + "section_salt": "A0318DC4C04450120D114911CB0F21DA" + }, + { + "adv_header_byte": "20", + "aes_key": "690CA5CE0AC60ADF00AE579BDB164319", + "data_elements": [ + { + "contents": "284488", + "de_type": 778 + }, + { + "contents": "2F9112B4015F302DD3068CB5C06236ACB4ED1ED9908BFD8859485E", + "de_type": 824 + } + ], + "encoded_section": "0230ECD327F2101FD57C67F868BFE5591A9EA0510A3A1918D42719B7D937FC25EB347643A382CB1EEF1BE0D45278B0EF49241FD4AA53333E9B20D7DF545644C794C0C313FC9C2D22968DADB4406A9E092999EBFB7F92", + "identity_token": "35AB8A4472A635C5EC6458F32686DBEB", + "key_seed": "99637210F99F390A997F576C706F9BC7C8581692E1285E29D1BCDE117CC0B428", + "nonce": "10CCB0A8DE6C3AFC5E747D1C", + "section_mic_hmac_key": "57447E9E35E7BF08280D4F92360E0141A766AA4CE818AAA45752563253DBD173", + "section_salt": "30ECD327F2101FD57C67F868BFE5591A" + }, + { + "adv_header_byte": "20", + "aes_key": "73D9602DDB93D7699C8C046E0B9E602C", + "data_elements": [], + "encoded_section": "02D74F68B471771AD2A4F8559305EC53902AEAF1CBF3D8C11992C5DE18AC41601310DD15D84C0CB36514110875BA8151D0EF", + "identity_token": "00EE8F5898673EFCC8D7D593ACA886C2", + "key_seed": "6BCC9CE0FCED7111026D0ABAC01E65F4149D37F617683A58960B8F4AB3DA64B9", + "nonce": "14B891CE7E628E756A830231", + "section_mic_hmac_key": "8A469C665BB030DFA05EBAEDEFCBA98BB35C9B9EBE41B1692B2D74ACB0973D58", + "section_salt": "D74F68B471771AD2A4F8559305EC5390" + }, + { + "adv_header_byte": "20", + "aes_key": "116268F2138D48B7377D1F9B993F112F", + "data_elements": [ + { + "contents": "142941", + "de_type": 384 + }, + { + "contents": "4E6B16DA0CD13D6EC21E797862C3AFDD25BE", + "de_type": 254 + }, + { + "contents": "B77B7519377B061318D90278B71FBA82C604D2DB5C69", + "de_type": 570 + } + ], + "encoded_section": "02BE0BB3EBC88AD859D7B875008C0931365F394AB17B39FB727A93193C4FEAC4E844DF2573378CFFA4B15B0D082B3D59EAB8373E20E17079FE768CA1A2479D57E002BC914D4BC807673ACD10F31FF5F6A39183669EC4B8F593E6E086C4456A3A872F3F401844", + "identity_token": "BEC77D2328CC57D22E0258715D0841E9", + "key_seed": "70FF80E5D4D65D6C8E4C68082D75ACD7B1EA9FD3C0F4AA154D4086D2D20D0A8D", + "nonce": "DC2D9C34D25C7E6D95B384F6", + "section_mic_hmac_key": "2FEE78E42D658EAE17656D3815534D07B399660A2030795ADEF7FFF532321509", + "section_salt": "BE0BB3EBC88AD859D7B875008C093136" + }, + { + "adv_header_byte": "20", + "aes_key": "52E5153F816929E66AB35A982F597400", + "data_elements": [ + { + "contents": "DF09806C22CEE77C4C664EFEE3288301768D", + "de_type": 589 + } + ], + "encoded_section": "0263497BB609ACDC19D570B16320321281AF7072F3BB15F889145ED8A9AE6E9F6A25CC28D879CFDE5740FA13C8E044D88BB6CA7A7DD16174A3ED805757529717CB260449D92B67", + "identity_token": "855F0220CB5E718D26321D4D7C7577C7", + "key_seed": "A1F0ABA90F81ED6943F95065A29589446498EC2F79520A56108539E3C30A19D4", + "nonce": "39A3380C10BB5CF8E9435BAA", + "section_mic_hmac_key": "6B654DBCC294323566E00D2A8C486A6F1ECB91FF949FA640B93D3B152F047230", + "section_salt": "63497BB609ACDC19D570B16320321281" + }, + { + "adv_header_byte": "20", + "aes_key": "B6E9D40607D8C39ECF7625E686CEF325", + "data_elements": [ + { + "contents": "2B2948F09099", + "de_type": 544 + }, + { + "contents": "E551587B", + "de_type": 375 + }, + { + "contents": "4E6F0748C486", + "de_type": 37 + } + ], + "encoded_section": "0205FA3C47404A35D4FD5BF0F547164C81B299006BA6CBEFBD4E0E4A450CFFA1382856C3C42CDA3A189D6FA37FFE8CA32EA8548FE61DEFAC42D1532D3865A41D6F71DB37B9C1DB88B1A3", + "identity_token": "72A30E0B2EF76A0265690E2564D197F3", + "key_seed": "13F03C6648844D00F21EA2CF23AC0B8284D36465438DE45C81A59775BA116FCE", + "nonce": "499227762DE0BC7B33BC7153", + "section_mic_hmac_key": "8714D596BE3472DF951E6861CA718DF4C391976F932EEEF3F8B48F78C2AF7C40", + "section_salt": "05FA3C47404A35D4FD5BF0F547164C81" + }, + { + "adv_header_byte": "20", + "aes_key": "2293B6380F70640ABA8871ED56932E20", + "data_elements": [ + { + "contents": "0479AB07E83192319E104D967353472F1DC0F863CCCCE0BB99", + "de_type": 258 + }, + { + "contents": "A0AC8E8D1A916AA5AB9E021CF32A85288F238809CBAE59AE8A71", + "de_type": 672 + }, + { + "contents": "", + "de_type": 27 + } + ], + "encoded_section": "0294E4D54F244E47A822FF413F6BC376B2B6162B1A181C00187B1ABDB43612153D4B8EA58CD0CFC7314AE91A06A4E35027FEB5EB8C9D93AB2872B2A3B561EDFD98F3A937890D95B5994729C4D04DB85258644B6E92E15E87C21CC5D567A005CF496490988A3AE18BAD1F233DE0", + "identity_token": "3AA3E8B81C9B7D2D22CFD1E3FD7EA5D5", + "key_seed": "DBC016C10B947661DE37B57C0C33FFBA01B89FD64B9417DC635D9D19C44511A3", + "nonce": "3F5472259721D69E0511C6F1", + "section_mic_hmac_key": "1097F2D8149337A3927ECD7E4E0534AE66E7CECBA50D8C8699E2747AAEEB82DB", + "section_salt": "94E4D54F244E47A822FF413F6BC376B2" + }, + { + "adv_header_byte": "20", + "aes_key": "BCAD6FBC54D804FB305B651664B5EEED", + "data_elements": [ + { + "contents": "98758452", + "de_type": 78 + }, + { + "contents": "816C9AADF492", + "de_type": 123 + }, + { + "contents": "C5AC", + "de_type": 539 + }, + { + "contents": "98C2695950C4B5C2F3C69D91B019D5045198846A088508158C4835", + "de_type": 929 + }, + { + "contents": "22C4B157B2334471749AB6", + "de_type": 320 + } + ], + "encoded_section": "028C8FFACE6BCDFE650833331F10BFDFB7B4E3B071CA7AC5CC1A3BAE79685825EA4FFA30EA2417529BFF840848F99C6A8243648D1F8244457FCA1F808E370B94D2F04BF78B7E51C23752D922268EB1443C0B08D3D2CEE883673ECE7AE5DD5EC5E99360901AFD815B2413BB071A62FF2960", + "identity_token": "A1D0AB03665B36F07643E7DEACE86D57", + "key_seed": "40A14BB11063D05593EB466ACA4C4DF438FFE2FDA5D874A4E5B3B4E79A6DC65B", + "nonce": "484B3BAE18B85C1027094E93", + "section_mic_hmac_key": "CE4B87F04EBF02FF12744FCAD9753239514C6E0856D6C2C6CA768315385A98FC", + "section_salt": "8C8FFACE6BCDFE650833331F10BFDFB7" + }, + { + "adv_header_byte": "20", + "aes_key": "B5CBEC978876F51A7BB1396D7A1A5796", + "data_elements": [ + { + "contents": "E55EF6F4749B6ED7F1E3254ED7", + "de_type": 427 + }, + { + "contents": "6B1F8A", + "de_type": 586 + } + ], + "encoded_section": "022FCDCA777563F84DDE7D907A02D77407964B19DF4F96C67E2F5E3078AD2D094326EC3BA4DD06CBF9CD27A0996D83942964893D079B8CA07E07B72D80482F25156C66BC22D60047", + "identity_token": "A1D64E8B5EF18E775F30C87C7F41937F", + "key_seed": "CF5EA21DD3F05F95A8A1658B4904E63F7ECBBDF860F1D27B88E4B418E914D87F", + "nonce": "C8C9C5FCF402ADFC23600F63", + "section_mic_hmac_key": "9768775B2D00E70743DB112CFA2E4DB37DB7D9D469E594D364EE254533F2714E", + "section_salt": "2FCDCA777563F84DDE7D907A02D77407" + }, + { + "adv_header_byte": "20", + "aes_key": "841D9C330BD88576BB9159CFD67F912E", + "data_elements": [ + { + "contents": "815DBB833846588103164057A0156ADDC531E401D585BD5368B419", + "de_type": 864 + }, + { + "contents": "2FA2A37BC6594C3B4A29A2BA077AB8F324F1C743354C2A1B97", + "de_type": 71 + }, + { + "contents": "E91DCCA08179D3", + "de_type": 873 + } + ], + "encoded_section": "02F49C8B85636DBD028678AA984B5A0F2643DBF77E8FC339E837757F1FE34403F353E16488648B5914A8EB8045BEC91AE34344DE4B90445DB2730AC1FADA1635D2DB87068BBA5ED44F6EEA57EAE2CA5B15BD5FDDBDC1C71C1AF39E58E2E2DDFD721C6E7B4CBBA4918FCC33688EC2119A6402854F69", + "identity_token": "27A1DED5C2E9533BF3F99698E1E525BC", + "key_seed": "6B7032582260EC0DA57AA5AD575BEFEC7D28696DC6035472F5745873DCB3B840", + "nonce": "6B048702497ECD3CADA72B3B", + "section_mic_hmac_key": "80747614953138AF6109362B19BD2C97FB7F8A224C908CA870258F1CFD5D6196", + "section_salt": "F49C8B85636DBD028678AA984B5A0F26" + }, + { + "adv_header_byte": "20", + "aes_key": "56CD7B921FCE0DC253137ACBEF4C9E7F", + "data_elements": [ + { + "contents": "8E2BA03625D8EB749839CA099D48DE15C7887A93", + "de_type": 194 + } + ], + "encoded_section": "02999AD00461B54D36BA7FC221F7F10D1239480EA7C91F1C200AC73639F608F5022706B4E495786CEDD18D582218A20C83534889C7026B633769D626E2BF60E33069B91D50A8CB1CEF", + "identity_token": "158D50035DE9F0289B63225B57629D58", + "key_seed": "CF8C5DDD57F9E7399E46F52E06906C39D6155AAB1BA940EDC3068F3642B0F3CA", + "nonce": "7E6FEF58E278A361FA3F77BA", + "section_mic_hmac_key": "561D62F4B1EC440C5A8C9511A0981C6A14F1A30EE5D156AC2460A25D9F2A095D", + "section_salt": "999AD00461B54D36BA7FC221F7F10D12" + }, + { + "adv_header_byte": "20", + "aes_key": "99305ED53E510A6A5620AF58B298A200", + "data_elements": [ + { + "contents": "BAE0D38B", + "de_type": 354 + }, + { + "contents": "CEC61AB08C2D8EF32C869D2FE2", + "de_type": 67 + }, + { + "contents": "0EF4293C", + "de_type": 947 + } + ], + "encoded_section": "02E368EE79CEE4FF33EA1BCF4950B8A8799DFA666B5562CA808D1919E6F24C5A3C2DB36770DB9C7514738035B233AB2025C66D50FA57008D76346564BD8D3BEDA68A676153B3638C47AE4ED7043A6F", + "identity_token": "9105B80384B6610035BC153B06A07D90", + "key_seed": "D72E99D75674D6C2F4E8EED8D64568DABC14FA7C55BF6F7E0B04302142474AF1", + "nonce": "61E591B344D506E266FEB0E2", + "section_mic_hmac_key": "501159272ABDB1D1BA4BE9311D77AC0559D63152DA5BD34A2820DA15A82AD037", + "section_salt": "E368EE79CEE4FF33EA1BCF4950B8A879" + }, + { + "adv_header_byte": "20", + "aes_key": "F9C9733A407F95BC056EA093672AAC62", + "data_elements": [ + { + "contents": "39A6851F0D7562A8D67C87847D", + "de_type": 33 + }, + { + "contents": "C7", + "de_type": 159 + }, + { + "contents": "C94372A46C75", + "de_type": 471 + }, + { + "contents": "E212FDD45F7031CCF2F0", + "de_type": 609 + }, + { + "contents": "60A513C6D691D578B1B8E0D8678C4C93417CCC8772A98A744EC6C3", + "de_type": 305 + } + ], + "encoded_section": "0239448EC52D1360B39AAF3D8D2ECBE21C8903D1847E324F6AA5575C8EE28D8E4157ADCE19A5988809B2C3396F2F55B8B1A6D7C14B509EAD06129426C91C94D7387DD790EF5EACA005EABAEAFF8D0E4E1A2286A3EBD393A0B0E2A0C73F900B32D82F28F3CF8441414116BC415BF3D652DC1F6ADCBCE89D5A5E", + "identity_token": "EB2E94C1013BBCE935289A687EE855F4", + "key_seed": "CF638C9E9ADEED53473692F67FB230EFCA033A90FB31FE01640296AD33198E24", + "nonce": "8A1421B5D302EABCB4E9AFDE", + "section_mic_hmac_key": "C0F1CC05E31EDC758059D4FA1C6A539059A63E86ED3A81EFE5B49ED6504BC816", + "section_salt": "39448EC52D1360B39AAF3D8D2ECBE21C" + }, + { + "adv_header_byte": "20", + "aes_key": "AA35088237F8B48B7B9783E54DCC7310", + "data_elements": [ + { + "contents": "C54293E528BF5A6D1C5299", + "de_type": 119 + }, + { + "contents": "B8F16ECD", + "de_type": 266 + }, + { + "contents": "C025E0", + "de_type": 749 + }, + { + "contents": "B668775936872A95200E2A1A544742E4B5DA218E66", + "de_type": 581 + } + ], + "encoded_section": "02605100404180967E0C35A27B303198AA0777DBC954ECAEC74857B598034CF02642E7BE5C315CFD1DCD1AB6164D1AC72EE44713D4332D0ACD1C0A588BB4DED8FBD841CC2D6EC37D6FF4DC1D9E3E1DBFFE520C351C868F4DACD799112FBE876903BD4DB4", + "identity_token": "681670B22B7549584CC281C7E9C7BDC1", + "key_seed": "5B8298AAA972242D14166249DAB29D642898C1EDBF4AEE35E5A28A523D79EF4A", + "nonce": "EAE83D7AF44006D4DB2FBEF7", + "section_mic_hmac_key": "D4810C45A1A468EFFC95E987192D01D0B2ECFD313E9852B1A3C914AEE1BAAB5D", + "section_salt": "605100404180967E0C35A27B303198AA" + }, + { + "adv_header_byte": "20", + "aes_key": "E6E881B42FC339A5ECA605018A8EFCE5", + "data_elements": [ + { + "contents": "", + "de_type": 486 + }, + { + "contents": "05BE835BECBFF491794F", + "de_type": 824 + } + ], + "encoded_section": "02BBDBD06DC3AB72F0082A6D0BC513951E56012BBCAAAC40D3F10B436E42DCDBD020E61B167FB0A77E527F3837E41D9AB666EDEF30B943B65984B33E7CCEBE0B4F79", + "identity_token": "21346A45B8489F23A9E63CB46B0AD4EE", + "key_seed": "D940EE0C157926DAB1DBF8020B86F06D152092B162CAF11C607B125A18FE58EC", + "nonce": "5A5DBDBC22E9F0485B0F0C4B", + "section_mic_hmac_key": "0BC02C5EB12F36E458141B6C48D553B9164D52F712BEDD2E0A7CB3FDB3C54862", + "section_salt": "BBDBD06DC3AB72F0082A6D0BC513951E" + }, + { + "adv_header_byte": "20", + "aes_key": "0E6F2D1663BA6A254DE665F436412DAB", + "data_elements": [ + { + "contents": "4E4693617BA9052ECC", + "de_type": 692 + }, + { + "contents": "", + "de_type": 510 + }, + { + "contents": "6DC4A08E16F5789C7F4CC0625715EC35E03DEC75153C98F9F3", + "de_type": 501 + }, + { + "contents": "72EC503A57", + "de_type": 283 + } + ], + "encoded_section": "02184D45A5DFF4F98BBA2B9BCCD0E66F1E6E4F2095ABB97491594F1E2615C6EEEA434ACD59264403E3B7C932D33D7AF49E223255148D5B9176DA76830D451DC226F6290B659EFB946BE7CB2F323D1AC1ED48187ACA1C7A7A1AF00E47D0A09AEA3D5B1FEED1", + "identity_token": "EF610B037D7AA8DB3C45146D1CF5510C", + "key_seed": "33D5F107E69D63BB05BD8CDDE5BCA9749BC619217585D756B67D84889942B812", + "nonce": "3600FCE45834326431FD54EA", + "section_mic_hmac_key": "36DC6B1B43D34B4A36A28DD14996986E4F3B14D346A24B1C7D5055202E1232C4", + "section_salt": "184D45A5DFF4F98BBA2B9BCCD0E66F1E" + }, + { + "adv_header_byte": "20", + "aes_key": "67C7EA4F6E8B95960DF747286E6C253D", + "data_elements": [ + { + "contents": "DFC4A6D167092E0EC4386C1F377C8D7A982D", + "de_type": 444 + } + ], + "encoded_section": "02AC62D0F2D343B4B67F2541B51FAB36F7DE79C99A6FBB63335DD4A5DB2D418C2B253164CEFA3BCB42A517E89BCD1FB1E5C6F04FA0C99CCB247F03D8A9575F2154D07D25D551BF", + "identity_token": "63E358995194244AD3281A35F844DEBF", + "key_seed": "AABF59ABBB17F47267FC66D84EADD558ED1AAFDEA87072FBAE1597E4F894CC2C", + "nonce": "438DCBDC58F3DC62CF4DD8C0", + "section_mic_hmac_key": "9C1F6AEEDBF0ED82872AEE17C94E67388D8DE56BF4E6D064B091F26314BC1C37", + "section_salt": "AC62D0F2D343B4B67F2541B51FAB36F7" + }, + { + "adv_header_byte": "20", + "aes_key": "CE4777B8675B646E84D6CBA4000FE4CD", + "data_elements": [ + { + "contents": "F1C005DE37", + "de_type": 856 + }, + { + "contents": "5CD278AE4F49F14B64AE6FFA980EDA5A30A96D674AE21E35EF1ACF", + "de_type": 669 + }, + { + "contents": "2CF1F076D4D763145F", + "de_type": 339 + }, + { + "contents": "E8EF398A871164F4AAC2512A73C2BBECD0ED64", + "de_type": 116 + } + ], + "encoded_section": "02777790C1F455A388A8A8908F2530F5823703F5594AF0E8BC06C2C683DB980BF2575C3006313D8F42FC9A6E4F133C88CAF4EE90C76199F59C6778C13865B9FA83AFD4C4E27F22E1857B682EE6401C973E67F6A04CB1FC1030861B77DABD0FD7018DBDD221F4CCC89BBA1423311439598E945890317E4DB25C", + "identity_token": "98BE3C3FDFF640C7902485986A54CB7B", + "key_seed": "8AC62E22A13FD1D0BC83021FBE72E253187FD032D48150CE2E363F0DCA427A01", + "nonce": "838BA90741E30DB71D749F04", + "section_mic_hmac_key": "CA069B89338B5A7AB5B6385DF46AD1EDBEE95EE58763002DC70201E132F0B98D", + "section_salt": "777790C1F455A388A8A8908F2530F582" + }, + { + "adv_header_byte": "20", + "aes_key": "73204F77542E61479FFBB70F15BE9D82", + "data_elements": [ + { + "contents": "E731", + "de_type": 228 + }, + { + "contents": "795B467FE034E95A4441C2E6E67FBE2117483A61793D21748522A4882BF8", + "de_type": 994 + }, + { + "contents": "0532BB79831FFD7B67D9FC26C7C25759EBE3AB6B", + "de_type": 343 + }, + { + "contents": "A488A172EFF5843E44EA9C", + "de_type": 28 + } + ], + "encoded_section": "024E89F9D070337876390A8DC90F532057A9F37C117727BDBBD0521775EAC63B345A3E53A0483357B963123F26B640EADA4F0EF043D4B25D831100557C0DF475FFC0A6E721D016053596B52CB0404090F67FAF7565661416996E3EB43882485EFA6EB866520D4CBB482F26EAEE25053B69059BF757603E9514DF131B", + "identity_token": "49A94C68702A530BA761CF9A02D0D447", + "key_seed": "03BA9921A9EC9DE1B4C3975F758B63E9D5110DA1ED0C3926D9B047804C36C525", + "nonce": "CA9A5E6F0D1FB66704D8835E", + "section_mic_hmac_key": "790DB507668CD2006E6C56455ACCFD851022A5FD00E5AD27DC3A7F011241EE47", + "section_salt": "4E89F9D070337876390A8DC90F532057" + }, + { + "adv_header_byte": "20", + "aes_key": "13A1E3A6D3075C5319C41E8467634AE0", + "data_elements": [ + { + "contents": "F98092C5EEE605C57E4F559DE1A39F6E097E90A6DF5ADD0516B1D0AE7C5E", + "de_type": 586 + }, + { + "contents": "9894D7", + "de_type": 148 + }, + { + "contents": "2F910D12E20F96F45D7E8D75D378C34ADC", + "de_type": 473 + }, + { + "contents": "", + "de_type": 382 + } + ], + "encoded_section": "0201E3D1E7546915A844FBAE96D804883DC7EE8DA279EF8B4A38498DBB4B05C1444E7A3076881D63895422DDC17BE94B3AB229D60FC56E3F7B356246DB710D92629B73ADD1F33F12518070CB4B6409C406DCCDE26A4AD9972FC8235F4912ED2538D0B9D6B8D736C9FA05BF569A9033C4", + "identity_token": "39D0F77560A9F411D420421C51345467", + "key_seed": "D752C5EC1FD70E7443A37506DB53F6D9E1D521779526D7458CAA5E0239027498", + "nonce": "14BBE83961C2E06DF151C3D5", + "section_mic_hmac_key": "290C81A58DFBE27E6FCB3DFE0BC632B9D929AC6A60527853230793FFFEE83969", + "section_salt": "01E3D1E7546915A844FBAE96D804883D" + }, + { + "adv_header_byte": "20", + "aes_key": "065DEA7DD770D48BE65DAF2A01922D92", + "data_elements": [ + { + "contents": "1B690D", + "de_type": 183 + } + ], + "encoded_section": "02006BF54BA34C5EEABE6733C40C6A4B9FEDB9B4127A2B99B33B12AA97FF6CB70D16AC7E7B3147A10EDB1F652024427E285A71D69A95BD2A", + "identity_token": "5CE752DDBBDE278BB19C9C3B3ED426AA", + "key_seed": "649A30B204D8F4A1B64EB975ADB6A2B83A7B6BC69728489535090564F3ABA77A", + "nonce": "454F3FBAA1278732E147A055", + "section_mic_hmac_key": "99262C1952E0E08CAC8768A100996C6CF6F1519EC57F18A0B1D73F5B2F6426FB", + "section_salt": "006BF54BA34C5EEABE6733C40C6A4B9F" + }, + { + "adv_header_byte": "20", + "aes_key": "C6F955057E1A4F1FFC1F2ABEA0B8FD33", + "data_elements": [], + "encoded_section": "027518E350DA3DC2A90BEBE9C1446ADC7DC841ADD922FC0E770BFF64583C4D9E7610A97E13326A236796EC40EC1C636A3B65", + "identity_token": "A161A4CC8259EB0F707BF4DF7B3DC27A", + "key_seed": "E73209D0C0D85198651F3B798FC53A0927DED2EEC6CE5B8EFB83E50BEF351209", + "nonce": "A5984AB79981B29B451A8BC8", + "section_mic_hmac_key": "A8AD4166470668BE0394BA7A2B9DD470F34C3BA85186BD1ECB8B00C4DD8C513C", + "section_salt": "7518E350DA3DC2A90BEBE9C1446ADC7D" + }, + { + "adv_header_byte": "20", + "aes_key": "5A3D5F583031D4031F313ECCF3E7CDD1", + "data_elements": [ + { + "contents": "7CA2CD5E09B6164ED80BDFD96614AB0EAF", + "de_type": 643 + } + ], + "encoded_section": "02C99D27CDFF106A9BF60401B30A12B78CC29E229B704A39A08B30A358EC76C0B124735CC7DA14B34B5D303B34BCF804C0FF5E6FB3A56426766182C9DB7FB908D4AA1DCB08C0", + "identity_token": "40CE8EF0C7FB9C8B822F760DACF25447", + "key_seed": "1928670C4B6F0DEBED5BAF7A97E950BBE94EC7D567A70CE967E4B2B212B5A7A9", + "nonce": "E8D11B32953AD61E43FF147A", + "section_mic_hmac_key": "4CFDEBF521FF7DF20B146DB5947E0939F80346BA991E4D06BCE88587B675052A", + "section_salt": "C99D27CDFF106A9BF60401B30A12B78C" + }, + { + "adv_header_byte": "20", + "aes_key": "1D8DA89F7A7D6CE5CB5AA18F77039AF1", + "data_elements": [ + { + "contents": "632D457E2AFD3A", + "de_type": 945 + }, + { + "contents": "E4B2038436599A2A4888A76F09A99786DA51BC3F", + "de_type": 628 + } + ], + "encoded_section": "02660B19D834927254C3CA4C44B4E58F9592C282EAEEFC114E0CAB05CF072BF7E5310DC0238DF9009FA972F31FDB78172E2D8751ABFB1B8D2C5A1472CB8AB52F915318FBEB98357115D69CB19FA2B381E5EE03", + "identity_token": "58CFED2666F58A35DB28BEFADE58C82A", + "key_seed": "4B54C23D5EE9BA26FAB0C9D819532B27104C3158DCF1204D2C90E493371465FF", + "nonce": "BC35F77BE3787AE9D562921E", + "section_mic_hmac_key": "832DD5525C889D87C58DFC886FC275FD53EF23602257DBAAADD8260445190895", + "section_salt": "660B19D834927254C3CA4C44B4E58F95" + }, + { + "adv_header_byte": "20", + "aes_key": "DEFCEB7C3979CDA6A93ABB83FC1B2D1A", + "data_elements": [ + { + "contents": "2D7A34E6CA20A0E05E4639488D400B35EA638CE6E538678F10BA", + "de_type": 143 + }, + { + "contents": "E84E413DC7B2226F720540790093", + "de_type": 781 + }, + { + "contents": "FD05E7976720868B46D00A20A71E", + "de_type": 358 + } + ], + "encoded_section": "022B54CE0520655913AD3C401F94530EE71BDFC769D515CB765DCA10AB115D32FD4F371FA81787527B9EE63C1D0B68DBFEC7C9651EEB12D6442CEC14CA7877CEE0261668C118A1A255A0994F5B8B7D86D5A6242B709350887160A90EF1DD0A3F0DBC402C8C114CD57EED600F0044C6E971", + "identity_token": "8C50C0ACF8A65AEDEB6963051EBB25EC", + "key_seed": "E78E6D29382220CEE2E4C81341D26B5FA63132186B82A0F0EC2A723B2BB184C1", + "nonce": "A3E85AD7D06053583B8A3734", + "section_mic_hmac_key": "E1CAD553106692395DDEB1B29597259001161AE17E76B7D1329891F98547002A", + "section_salt": "2B54CE0520655913AD3C401F94530EE7" + }, + { + "adv_header_byte": "20", + "aes_key": "4357834BD8534421FC328E433DC7B1B5", + "data_elements": [ + { + "contents": "A0B4D6535ADDE0", + "de_type": 842 + }, + { + "contents": "82B652635D1D50ED2BA2B02EB2C724B314C1F528079AE302", + "de_type": 350 + } + ], + "encoded_section": "02258C3D33CE4C862F9B69FAAD6C1BFE1F1F8D746B94BD1AB65354B648AC0D054A35385EF82E5626CEB99335CF2637088410D4B278EC77451E3C9AE2DB438AF702EA1327B74E5B341CEE8D2D1DF16A482EE18DE4F8511B", + "identity_token": "D53777A4358E0F2A2EC95AFA3D408870", + "key_seed": "A01B914623D5624DBBF6DBC8757BF955A979E32B187BC7F70E3EDBDB95C4716F", + "nonce": "B55F4A96033F23DBB8BD3F5C", + "section_mic_hmac_key": "13A8C92D1F018B4F892D459BBFFFBA84307867F39B300918B0D6518766347554", + "section_salt": "258C3D33CE4C862F9B69FAAD6C1BFE1F" + }, + { + "adv_header_byte": "20", + "aes_key": "326371E295F358C8F1237CC22F501666", + "data_elements": [ + { + "contents": "6C378A24DE51EE42", + "de_type": 264 + }, + { + "contents": "248624F8FF242C90854382BB24", + "de_type": 248 + }, + { + "contents": "99135A2BC5D7D748EE152CE572FFC032207AA2AA605D", + "de_type": 514 + }, + { + "contents": "1EA3BE72AE386B6F42", + "de_type": 820 + }, + { + "contents": "94AC3E25F14015AC7C7AAC7E611A931FAF59A447F1D3AE", + "de_type": 708 + } + ], + "encoded_section": "023B3CCC62107DBA3672E653B736AC923AA99D7B440C792BCA1D85378A240F0D766A47C965608B564999D496CDA5185BA9180928BCA9C43D9CDE40A6F8B5E52141EE95718009505ADE7B0D5285867B634ADEF94FC38951BD92B98C4005CE71ADFEA83040140F00688181B3763809B99366E69077DF00ECF3CE124D629BB0AA5F49A2378DCB05EAE7F9D64B38", + "identity_token": "53E15A1B5692E1BE92BD953C353F7B91", + "key_seed": "8DA28C3966FAA33B3C7302CD269126F56D184CFC10498ED7969A288AFB0DA616", + "nonce": "F4839E1496794C1F01572669", + "section_mic_hmac_key": "B65A6625E49603D87BB9CDF3D5B0D4C2DCDB4536F45A953A67FE6F101C1AE798", + "section_salt": "3B3CCC62107DBA3672E653B736AC923A" + }, + { + "adv_header_byte": "20", + "aes_key": "EDA860E0707ED96A1172A45CC0811384", + "data_elements": [ + { + "contents": "29", + "de_type": 305 + }, + { + "contents": "B72753", + "de_type": 903 + }, + { + "contents": "6983195D8AA985C58DB6DA9ADABBB38DB3917430F36372", + "de_type": 540 + }, + { + "contents": "BF901CD8", + "de_type": 951 + }, + { + "contents": "A4", + "de_type": 859 + } + ], + "encoded_section": "021026C610CCE881C1A6126022EFE069A66FDB75AAE177D28EAD4AEC586AE134F23F54F49C0E7D888DB5DD850D204030D83C303EC74ABEA7876345F687BBAC70AC0F1C47D6FF493166B00D002A6E7B89CDB7E10E921F081D8C674D10E2D2633E92", + "identity_token": "A3D9812AA67DE7AFAFB41B411582B2F0", + "key_seed": "4A23659FB7CFA0A0E73DE712ADD01F8FA0E7215FF8CFBD35771236B60A387011", + "nonce": "53E571E0DF89BF6C7216C7C2", + "section_mic_hmac_key": "5ACB14F2E5F318A1C9D769FFEF152293CF1A0A37B735153951DD236CA6DAD527", + "section_salt": "1026C610CCE881C1A6126022EFE069A6" + }, + { + "adv_header_byte": "20", + "aes_key": "6AED67F14438D7D911EDB8D722F488BD", + "data_elements": [], + "encoded_section": "02F4CA6005D5468E98560AC1A7EF01DEE90F3B25A4E8592F10463ED297782C65DF10AA8303AD3B3F647B0B35AB90E3751E3A", + "identity_token": "DB6F1DD46763D8721214EA515B47CFFA", + "key_seed": "F86B31559658B13CC4384D00DDA8CA7924F7F545DCB973E94AFA03D006B8E305", + "nonce": "A7702BAF126B2CBAE121878E", + "section_mic_hmac_key": "1AE36FC285306CC764C77EA289920D5428518672A3B9A5941C02DC4D2C836231", + "section_salt": "F4CA6005D5468E98560AC1A7EF01DEE9" + }, + { + "adv_header_byte": "20", + "aes_key": "6B926CEBE38D4132E4BE5532867BD395", + "data_elements": [ + { + "contents": "67B6BC35D8B35057BFC81EE006076C575766A1", + "de_type": 148 + }, + { + "contents": "3D2F96ADD78DEE2E928A2A6D1452AC9B5C", + "de_type": 830 + } + ], + "encoded_section": "02C4D4D2A92767AA88EC70C16EF70254C5028B41E18F6CFE231D87F6DF5CCACB1E3A2A223140474CA5A48FC80DEF2A64251E63A8645D1B338045BE4F1755E31916DC8169AF62BD094E015DF416DCB929C6FE9419C0E553CCB48BC8B8", + "identity_token": "9BD9767523D8349176EB79FAA07CC03F", + "key_seed": "9D09EA97DF4EEC2BB30BF025A9E6B81BD3EEB19870BBA43A4EEE452066BA7F03", + "nonce": "5B6638F881B5983B1A5E97C2", + "section_mic_hmac_key": "8F6F64C6F8626EA4F63A0B62B87E5A9F25A5ADE408E1E829E06B952BFC1FC419", + "section_salt": "C4D4D2A92767AA88EC70C16EF70254C5" + }, + { + "adv_header_byte": "20", + "aes_key": "BBCA7CCF407D135B2E4E30F2F2D5BECF", + "data_elements": [], + "encoded_section": "021AA76A19C77A439E19ADB69D70B0DB1C25F4EF40194EA5874083980925FE7A7710C4C42DA77C168CD699E7ACE28920571B", + "identity_token": "5350E2CA3B7927CADA9D6F2B02C28310", + "key_seed": "1B679F25EB8C387B01FFB315A1DB04D8981936963BFCAE20BF4F5524C1F762AE", + "nonce": "182CB56F4E9A946E490A066B", + "section_mic_hmac_key": "F7683F77117946A69929DBD6580EA3311C1DAF13C3755FDF052DCA96D0685970", + "section_salt": "1AA76A19C77A439E19ADB69D70B0DB1C" + }, + { + "adv_header_byte": "20", + "aes_key": "52C67744CF1B5AE97F091C915CFAA6A4", + "data_elements": [ + { + "contents": "0A882289B49B", + "de_type": 860 + }, + { + "contents": "38DB2A68327F6FFCDDCB2DEAE4B4D7C1C68FBD52F18711A8952AE1CE", + "de_type": 586 + }, + { + "contents": "E89FE85C63F175B22F6D373707D9C51F7D062B7278DFEB7F2699041DC4", + "de_type": 403 + }, + { + "contents": "FF6658532AD2EECB814EB0A5BF41", + "de_type": 63 + }, + { + "contents": "FBAA7E6F8C867A50DA6EB4F406B7FEEFC2378AC3CF45F1DEE9742FC9", + "de_type": 910 + } + ], + "encoded_section": "0240A2448B3046FFE23A82D40AE027B410210C3D699F8057821BCB3C7465565CA087A7250E582F9AA365F5FC4E35F1F1340926427605DF90EED725463E57D16453CA4D3AC95BF35434676E3AA1616176E89F53AC9224003690DFEB64DB256D9DEFEDDB93D9393DEFA3A5BC664C8A234118E5548A6495334FC717CBC4571D2152B6D28FE4EECDE4F3C4179C62CB02BDE28EC7A55C029E3030A30407028FE1A4CE0925F431A2B14437E6", + "identity_token": "44CFC684E6C7050263E2CAB4D744A814", + "key_seed": "9A30AAA2B9A12B59236DB28F6761EFC40CCDDE59A07518BDB19D45BA2B72BF26", + "nonce": "AD0E77BB4D951804E67A70B8", + "section_mic_hmac_key": "CEB035A541C1D12C0F02B861402E73D21C8F4C2EC5C4C8DEFFD1623EC7FCBFDD", + "section_salt": "40A2448B3046FFE23A82D40AE027B410" + }, + { + "adv_header_byte": "20", + "aes_key": "23F75DC56095B764A3367B0BAC2CAB3A", + "data_elements": [ + { + "contents": "3ECF", + "de_type": 825 + }, + { + "contents": "A0A7F010524BB3B0CF95D62762830DD0192486B2C21E", + "de_type": 307 + }, + { + "contents": "E58DB864D613F4CF4B613B0F9103BC14841C7B00ACE1CDDE594E448F", + "de_type": 769 + }, + { + "contents": "84E31D1747DA456817", + "de_type": 98 + } + ], + "encoded_section": "02E1422169AFD9B4F1C931B65EF8BFCB907E66B43EB676DCF362B31F339BB43B1A58B6D6E192491D7C136397078953ABB335D77668F6EC744FD67142A16C9FCAE8761E4F8388E8B0A2DA4037AB767EDFF9A9A30E209A8D6E2E23A371C4085780A50EDDCD91B895442DB896B38455B9221B3096C69684C14599AC", + "identity_token": "10D4BDF9C47D2AB3EC885FBD625C0246", + "key_seed": "1FE48B81802881434FD77BF3C21EC0E8858AF9164C27C74D0F4B362F0EB5C528", + "nonce": "833F029D2BD54533FC3E70BC", + "section_mic_hmac_key": "78F4C0AAA20F8DA2EFC963344E5926EE8A07494B48E778BC158B3997AB2B6285", + "section_salt": "E1422169AFD9B4F1C931B65EF8BFCB90" + }, + { + "adv_header_byte": "20", + "aes_key": "7617C16EFAEF5EDFB06625756362C2A0", + "data_elements": [ + { + "contents": "E5D673BAFF29A4D3C1", + "de_type": 270 + }, + { + "contents": "6A57381D", + "de_type": 887 + }, + { + "contents": "0E556091078C6748C36BAF40BBB4E4BB", + "de_type": 205 + }, + { + "contents": "2055F5870F08F9CD3EFA17955C99F226404A", + "de_type": 383 + }, + { + "contents": "C8A4A9A3FA548102A1F96327A4287A70D500DE35862AEC8E1AC6F1DB84", + "de_type": 628 + } + ], + "encoded_section": "0279C36005CB2893825C08AC9D00C707FABE695CE889681CF240A6D97597ED0E7E6B4B7EE58F722D9DEA51FF86226C332E4917FA9E0724B39DBC3C1C9425F4CAAF49019E646B21816BA6B92701E19118AA31321C1ACC9725D4B7AECE13F56161A978E8F646FBEF9A61498F657340BB21E8D96E8F1980F62FF69F92695C6164D59D271991E38B4367DED244F3C4", + "identity_token": "F65402F8A50A61A802B8D5C12F7B6139", + "key_seed": "91E49925060895395298594A49F168FC765017D07C6E7A111FCED5C43A0C3A51", + "nonce": "5E14CA25F6C86D3DAAAE3A82", + "section_mic_hmac_key": "F81460B1DA857EF01821651349218A0B6DA51DBD2338913621264D75C0EA0BCE", + "section_salt": "79C36005CB2893825C08AC9D00C707FA" + }, + { + "adv_header_byte": "20", + "aes_key": "7D5C69BCCFE498E5464BEDDEFA884421", + "data_elements": [ + { + "contents": "445E8055", + "de_type": 714 + }, + { + "contents": "2098DE470E2583D9FC2E040859F58B2C45D3", + "de_type": 769 + }, + { + "contents": "72BC2F855131395E0C6C0E5814B02D406724A11179EC", + "de_type": 799 + }, + { + "contents": "7456300CB3DD5E", + "de_type": 241 + } + ], + "encoded_section": "02FD4D5055F7192BE8BA25A2FA5385B5D524CDE482D669C0E529D5308E322AE8A14F3A9DDC777769014856F0A8E6A042F1C05FB685E2E14E6B63F18556036E4D68A37E9941D7BD4F583C469D5F37105A22BE25B994D2227206DFE0922276D6375D480C08DE38B82D8DE92B0ED8C7AA1A37", + "identity_token": "AE507BDB86B14FE8EB76147249EC5865", + "key_seed": "797EE27B2E559335E524718A4346DC8823367D14A7D7242B0645A103D1E73391", + "nonce": "13623B08CBFD928C92254CFF", + "section_mic_hmac_key": "409F3A5462F5B64E15C9264A981ECEDC489C5779AAF29CB5523714DBBB82A06E", + "section_salt": "FD4D5055F7192BE8BA25A2FA5385B5D5" + }, + { + "adv_header_byte": "20", + "aes_key": "F5F75410EF7DC53152BD2130C6327171", + "data_elements": [], + "encoded_section": "022252124D2BC9B6498FDFCCD0196CF4C56B993255169168AA337B00796E3C0DDA106B5F1F519ADC5898F7F5661895462E16", + "identity_token": "E18F1D6F8CEB5CF84C941AA47C728D66", + "key_seed": "4A01C7DC09BD3999C74B95A6B50FC0CFAFEE1E36C260026D0DD46F21C56D82EF", + "nonce": "497A0BDB69B6E6258A1941A3", + "section_mic_hmac_key": "B4D73916A49E25F62EC59C9E9B24A347EB1A5B95694681467B8FF6EC79A3EC27", + "section_salt": "2252124D2BC9B6498FDFCCD0196CF4C5" + }, + { + "adv_header_byte": "20", + "aes_key": "3A64FA90D74450D083302E2C059C9665", + "data_elements": [ + { + "contents": "CFC759543DAD41C009FC402A", + "de_type": 988 + }, + { + "contents": "786F5232031993953C6A9A08C1976E8C30BFF38FA84531086FF19DFF", + "de_type": 846 + } + ], + "encoded_section": "025F023F5D79C52E9DBAB9F0DA69237D642DA017E11913BBB351FAA7067EB3B06A3E8BFB15DE59E4CD1C3444935A180C26E58FCD08650970B216E1CEE4E8E96A4EFB59E03AB6409A5FBC07282CAF51181B8196D0D6DD95D424076EBA7F4C92AC", + "identity_token": "71E0154EC5B0D069EF2CBDBE4D4F64EC", + "key_seed": "076E48318DBCAE9AC52822CCB8C328E8E526278A881C3E777285843D900DC7C3", + "nonce": "B81706D97EDB8A2F21130E10", + "section_mic_hmac_key": "5F5F097D7C90D9DD993E554E3620ACB5E32EEED68D0A70C8D0A96B9E8FCFCE0C", + "section_salt": "5F023F5D79C52E9DBAB9F0DA69237D64" + }, + { + "adv_header_byte": "20", + "aes_key": "B443584BA0695A5DE100FC7E4471F096", + "data_elements": [ + { + "contents": "8D07D7C161B1E3B9AD44036C9152", + "de_type": 568 + }, + { + "contents": "241997237B", + "de_type": 304 + }, + { + "contents": "EAE8BF35970B3FA758ECD25FAFB52DAAE97E90AE207A5AE1F65EAD0D49", + "de_type": 240 + }, + { + "contents": "C3BEE2960CA3C9BA732858B26600209CC17E277BB91578F7F992A7", + "de_type": 923 + }, + { + "contents": "FAC026BE6D3446FD6C7EA221B4", + "de_type": 282 + } + ], + "encoded_section": "02AADF94195BB7269EEA6B86F55F8F625EBAB866B50BDE8C3963CEFD8AF4C6415F77869D51C5DF0D1BE02D052056B0A8EC667DF3E294C898501276BB22C0657468C4BA18A25F35C4C3EE4A233A77C5C3C77F23588264BDE91EE9D0B00735C5A5DFF02F97849972CE1FF1CC5DC22200D33DF6FD1957F9CFE6C42242B63563BEAA654E63F10611B4C43262949BA084C9ADD9DD34430D71A64D68", + "identity_token": "F73F1700F798A87559130AB945C74741", + "key_seed": "DAC1B91B10F16C4398EF7C8058ACCAEC2A9B30A0FB9AD66E121DD19CDAEB37A0", + "nonce": "2EC6381E4B347BFED3E91754", + "section_mic_hmac_key": "642792EDF30489843D0FE58973082D231FDC14BE72A4C007BBBBF85CBE8757A2", + "section_salt": "AADF94195BB7269EEA6B86F55F8F625E" + }, + { + "adv_header_byte": "20", + "aes_key": "83EC80F024DF21B65CFEFD1EF94740E2", + "data_elements": [ + { + "contents": "27A69E731F", + "de_type": 287 + }, + { + "contents": "DB716058E34CF7B472543BA8", + "de_type": 576 + }, + { + "contents": "5672B7B1AA5E483968D00E77AB12", + "de_type": 124 + }, + { + "contents": "F46774", + "de_type": 705 + } + ], + "encoded_section": "02D525060ACC8BA94C63CDDEC60BEDB5AD791F43370ED6BDE4CC9BAE70A03E4C9B3D33536D52A575D5C02DD67E91BED7C3DE179AFC1C035397388F48297764EA4E8C329557E6A71FE5A63379A8618777524C2AD19E0A9BF1F65F6BC54C076C", + "identity_token": "DCF0C0BC6CF0AED2BB98005F9BD314CC", + "key_seed": "40402744DE9F4976A2DC489058A6E3392FB0B9835DB8C7018E678B3406C4441D", + "nonce": "02DA50D948182D528619E7AB", + "section_mic_hmac_key": "035640B10657D96179E987095B1D01D9A98C6158A98726FDDFADFCA582268F9E", + "section_salt": "D525060ACC8BA94C63CDDEC60BEDB5AD" + }, + { + "adv_header_byte": "20", + "aes_key": "0418BBAF50BB908526F913583233E243", + "data_elements": [ + { + "contents": "F45CB09C4F9BCC64CEA8729CB757EBB30B9F35DDA00494D9DB2CFF53ACAE", + "de_type": 909 + }, + { + "contents": "50F3A9F85CE86BB46570EC179649CACF30E68184C26F0EF029D88AF32869", + "de_type": 47 + }, + { + "contents": "036508751C50D9C40FF288AC9CC81B46D0CA17", + "de_type": 498 + } + ], + "encoded_section": "02CCE7901E20E283CD0A9CC73E4EECE408A6D1C01EDC8574E8FF9F2D4E1F07CB7267AC537E5BC0F41CA06B85E63818B10F5B012DB59C0D127A1AF043750A04910CF3E8CFCD245190702461AF431A690891BA9B37146990A0A330674F9708D25B3730D5B23A4DBEDF46694CBF3D7AA4CE6C35C8CC833A22B82B74A3858DCBFC262C065EB5A5DBEB36B7", + "identity_token": "F8D68732B8CB236625F2F9FE6EC1DC4B", + "key_seed": "A2BA315C4719A6F2F908D6662DBBCB072B283D419F9A56B79B2B6233E96C21C7", + "nonce": "1B41FBADE98FA042E9FEC7C3", + "section_mic_hmac_key": "72F23D0F266F564D8D5A2545426A7CDDA3F7D20D43E372CB6EE46D85871537FA", + "section_salt": "CCE7901E20E283CD0A9CC73E4EECE408" + }, + { + "adv_header_byte": "20", + "aes_key": "E2EE6FE0CCA11951F4854DA7BDA99ED3", + "data_elements": [ + { + "contents": "C40552987F158C0CFC56EBF3", + "de_type": 321 + }, + { + "contents": "", + "de_type": 503 + } + ], + "encoded_section": "020E4D5C6ED93B014055B8951F8FD220A57D827187D544B46DCD6ED9432B424F4122E01AC41591CB4DF89F5D00410412A7647452BF4AE9865BC9F337CBC12706F1881985", + "identity_token": "F46324863C329E19C0522E7AFB0D9B82", + "key_seed": "43766BADDE1B80B6598CA446112A8FC98DD42EAB244B3DEBF08302D7BD4FD376", + "nonce": "FC43822BD63D014A2ABA6479", + "section_mic_hmac_key": "DF4154082EFCF4F670B87A36A31E095ED7B7AFBF8C324D9F8E0D29E1EEE8F7FE", + "section_salt": "0E4D5C6ED93B014055B8951F8FD220A5" + }, + { + "adv_header_byte": "20", + "aes_key": "77F690701DDFD7AAEE15B393CA8E4113", + "data_elements": [], + "encoded_section": "029E470E6DD0076A256D60553EC207DA37F38577FBF8CB639C6E8F84A4502D5CAD10B4F17F4720071345C051290A66EE1347", + "identity_token": "AEA2B76D803628E0426E64AB7477B395", + "key_seed": "13154557990A80FB24A70BCE09BBF62DAC2C95146B1163508D9CACEE89C75D96", + "nonce": "6B54C468B6CD60C9BCF05C06", + "section_mic_hmac_key": "7C56EF628CB49E0E3439DBE47034A4EE4D74CC431D919E7ED97F31B7C4680D00", + "section_salt": "9E470E6DD0076A256D60553EC207DA37" + }, + { + "adv_header_byte": "20", + "aes_key": "CF0F755BC0929BA3338B04E0126BC444", + "data_elements": [ + { + "contents": "0AA5A94208D57B66ABE5B8341167C1544ED91B35C6", + "de_type": 695 + }, + { + "contents": "3E39B499E2B74671EC3A54CB", + "de_type": 920 + } + ], + "encoded_section": "02ED8065C1778DDB635023F96FC9DB4B43C2FCFC10BD074146EED51E7F9A46C9C437F01690BF9BAB7C0A9964BFDAFF313CF0B46D6387B78922EC76F009B1C9D11C103F54DB4B6C2CC32CFCE97E2F3349B91AF70279128DDE2D", + "identity_token": "0A257DF8A7692B3249407E160C037F32", + "key_seed": "3F64813E8A4B3DC815206ADADF36DB6D66B9BAD623636491CE3A47A85A80ACE1", + "nonce": "E1AA1F6A438632C46B33AB73", + "section_mic_hmac_key": "A8A1D0BB14D04085F5340F1ED0AEE5C2201BD4EC668991370E804DA18EC94CB5", + "section_salt": "ED8065C1778DDB635023F96FC9DB4B43" + }, + { + "adv_header_byte": "20", + "aes_key": "08851035A5C0B4211E613496BAF5EB58", + "data_elements": [ + { + "contents": "C0D408E8EF9DDB0E755EB45523D250D58B7F5B647721C03ED8", + "de_type": 21 + }, + { + "contents": "0BD5FAC43AEB6F8CCEB0583EE744B80A897ED7558D57DFD06BB81C", + "de_type": 323 + } + ], + "encoded_section": "022C1DC1FC780C25AA2E4852BA8CDB2BCB44DBC4820A019D95184F42A70E419861498AF4A6CD8AC3D9E110C0021461F9020233FBF843404099F378366DB902EB106947263B984BF7D40116604F55C42DB12F25C686B250E139DC1C994CDF5E7C1CF308144E294155D20AD3", + "identity_token": "776B3A62CB93BA94651552C97A2E4267", + "key_seed": "9509B69A6A2BB6CCBB1A1E7436E77AFC2D00A2FABD2A1665A7BA6FD6E33354B3", + "nonce": "42DA14BD4FA470084787B4EB", + "section_mic_hmac_key": "603743F9A5815E17229E364C363DEAB2ED6341B86E6D6A4F2F723629272CD0DD", + "section_salt": "2C1DC1FC780C25AA2E4852BA8CDB2BCB" + }, + { + "adv_header_byte": "20", + "aes_key": "B60EBD62633BB487ED9F7D9E426A0D96", + "data_elements": [ + { + "contents": "7A0AC4F78A416F5B0114535909A5307F", + "de_type": 902 + }, + { + "contents": "EF581947C68D9E50AA05", + "de_type": 46 + }, + { + "contents": "FD", + "de_type": 888 + }, + { + "contents": "FD", + "de_type": 315 + }, + { + "contents": "CEDFEE9059F500C97D25C94F", + "de_type": 7 + } + ], + "encoded_section": "02DF453EF92630EB12DC02E3EDCA4A36A08BA4F34CBFA1B595CB3A6D01C58724D0455434E8D72455F125B81A186A41FA589EE9710ABD7F9F67E011912FD0DFB2337306AC59112298BA20EE5FE66227AB94034D13388BB4484B8A6587A31F0234024115F6D30CF9", + "identity_token": "A1C908312B87892BB9828075C672635F", + "key_seed": "6D32B114EF3DF0128A529FDF8B2E7EFBAFF451FAB30302DDD8BCDC811D0FF0AD", + "nonce": "720138995818A3EE421768BF", + "section_mic_hmac_key": "9243F2687949CC4D05AEB4D8FB77890569AD61591E37FF206959B6CF98342BEB", + "section_salt": "DF453EF92630EB12DC02E3EDCA4A36A0" + }, + { + "adv_header_byte": "20", + "aes_key": "DB1A823A46931F80A323BA830F003123", + "data_elements": [ + { + "contents": "8100834C61C6C93430E5C7BD4B86866C074468", + "de_type": 0 + }, + { + "contents": "CE623A4184335F6C9D55A7A2FE02478336DDF05D8F4BFFAE", + "de_type": 238 + } + ], + "encoded_section": "023AF28C09CAEC840269BF5DEEEB2AA95C60E64AF819E6A97B8ABE980FD7320593400018850FCA6227B727F1ECFEFC2B74B62F21E44B40B14500E9736646713FE6B65DBCEA9A39CA410D4F4E7C25FC753BF4E89064485C09E8B30D936CF3FC31E704", + "identity_token": "0758CA3E92715E8088FEDB4D069661F7", + "key_seed": "46F7E0CC1B0AFF6971DE8E4AF1BEDA76D5FBBBC1673D67D5E3592207241B03CC", + "nonce": "CD05581E1D32C9D6F251E1DA", + "section_mic_hmac_key": "7EAE309E12347554A36BE7F5416BC98458A6BBE1CE11812AF7E1E0170942DE7D", + "section_salt": "3AF28C09CAEC840269BF5DEEEB2AA95C" + }, + { + "adv_header_byte": "20", + "aes_key": "094545346D6DA2AB87E9F21C22EBEB5A", + "data_elements": [ + { + "contents": "FBD5BF3B86FC4DF98299A04516E245CF69BD201E44111D9F58835F", + "de_type": 962 + }, + { + "contents": "7A00781BDED3EB83ACB0F347A49F14D039", + "de_type": 611 + }, + { + "contents": "42A41A496D6BE276833FFFFD2778E555A4ACC09190B60594CFAA1F", + "de_type": 992 + }, + { + "contents": "F86971896012BD", + "de_type": 517 + } + ], + "encoded_section": "02F8F5300B7A01F96A0B73610D4A82F877EC68C96FE249E235C18FC5856E98E4646AADE7D3002AA4F39AF7F2113392EE3C6521AAB6EDABC8A5C5CD33275355C434BA00554158FE2207C510267BB6A50B721D2BF1DB8A832CEE8C1D09CBE920E9B9AE68686B7393211E5CD0943C97A76CA8A0FD82B18CE06A7ED92FB378BE450B6930A6F241B1D2696E80B598", + "identity_token": "6F95D140C0F87F34DD4CE7CB17CE8609", + "key_seed": "0CCB26C7DB958F8435D66E11D6A68875DA25E7D12A11EAA58386A2290A42027E", + "nonce": "6DD2B018A20FAA4E46703F7B", + "section_mic_hmac_key": "D5A0F725FE6E6D8BDC79C2C668196D3303D6465C92D478BC676F91C1A462E024", + "section_salt": "F8F5300B7A01F96A0B73610D4A82F877" + }, + { + "adv_header_byte": "20", + "aes_key": "621702EDC90A5A8954B64A8CF883DAC1", + "data_elements": [ + { + "contents": "09", + "de_type": 482 + }, + { + "contents": "D5", + "de_type": 698 + } + ], + "encoded_section": "02B14D7C2C925F3E24ACB1E4A5D4DA6F193FA87DDA8E2FEF20F01FFB5ABF3B8CFC18B5ABC3BB0FA0C46785729CFCB9192442D7DCF702EFC0304F", + "identity_token": "9E6F8A6063A6BDD60D5954F592A3B8F2", + "key_seed": "C62E96131C7C8B805CC9FE6FD634CB9BF84BD4984529B30576B3F3856CF04E63", + "nonce": "0FDA5313782FED9FF7E65C4C", + "section_mic_hmac_key": "89023EED69C4E5DA5ACD11E15AA540323F2EA47A19E4937C19A10DB89BF9A735", + "section_salt": "B14D7C2C925F3E24ACB1E4A5D4DA6F19" + }, + { + "adv_header_byte": "20", + "aes_key": "B5CE72C63EFA9DD095716472FAEE0784", + "data_elements": [ + { + "contents": "DC06F9FBA5ED966657D9CFA8667DC006850CF89899DD", + "de_type": 989 + }, + { + "contents": "F68AA9DFC06B7EB7D9CBBF5EAFA968984A100C2B03C504A5E1D9C7", + "de_type": 706 + }, + { + "contents": "055D1DEDA05C238D7A31E5CCAE", + "de_type": 379 + }, + { + "contents": "5D1B64B0D53EDAE32FA989CCC38E1B2ACEAEE0930EDC", + "de_type": 221 + } + ], + "encoded_section": "02E1630DAC1DF049E06A3020858C0857589FF7482D737059F5C999422EC552C91670AA375473BE99ADE7BEBCE8F54E3EA98B2C36D02BAF87EAACB81D0C461C824138DFBBE8BDF53FA7E19F53BEEE1EC2E228956F551335C7BE1FA38CA5933DE6AF767650F6B00C4CE3F7FEC0ECEAAB12811D79317CE035BE9E5E19522A1E329CB0D9B6FD0275F619D95F0BFDF8F071C4FB0A", + "identity_token": "57EABE3C09AF926FCAC347ABFAD9E33B", + "key_seed": "D3E7B4BD3F00BB656B34B68A9B57D3499B1690439F52E39BF55145069B69E012", + "nonce": "70AA23057C2F616829EB283B", + "section_mic_hmac_key": "6DF923F1C439D6DCB1D17267F1DCF9F77974CA0CDF3815525FC480F56FBD46C7", + "section_salt": "E1630DAC1DF049E06A3020858C085758" + }, + { + "adv_header_byte": "20", + "aes_key": "E257258A3F83CEC8750E338556A3806F", + "data_elements": [ + { + "contents": "FC2AA7F38F27003ACE8033FABCE80A1A0A2855", + "de_type": 534 + }, + { + "contents": "93CFA0A1BF2C1517B833EE189ADBE984348FE43D91B738D1D51B1A52", + "de_type": 317 + }, + { + "contents": "4883BFDB2678", + "de_type": 899 + }, + { + "contents": "EF90D2A4545867C3", + "de_type": 654 + }, + { + "contents": "37C02A83E008FA26", + "de_type": 532 + } + ], + "encoded_section": "0289F842808FD5738C338616A2560581A8A52F4A6E16A6AD73CAA41028724B501D64C5800CE30D76F8D3BAD6CD098CDCE3FEB9F4425CDC836605063FFC21BCDD041E0158EB7478416478361D4E2073A9E1C61EE770E179998E0211D0B225F1F59C2B9392F5843E3E4F99716B356E52081797EDA99115FC8A0012D55A0C3D119117D0D98F57AF", + "identity_token": "80FAE8E4817345A5115FE9556AA13FE2", + "key_seed": "C6044A22FEF3D9547667D2B2E2BDB95FE9E436B43F7137CB775B790BBF1C5914", + "nonce": "DCB6A5793686750BFF4725CA", + "section_mic_hmac_key": "B2A815D44780CBD0317F016087313B40970A52496DAA6B665EDEEBE1287BC499", + "section_salt": "89F842808FD5738C338616A2560581A8" + }, + { + "adv_header_byte": "20", + "aes_key": "C92370BF646709CC74E15195B1ABABD1", + "data_elements": [ + { + "contents": "BCBFD4CA484D111FC650E199022CEDB4472F4D9F59C27551835889B9", + "de_type": 89 + }, + { + "contents": "479B03", + "de_type": 87 + }, + { + "contents": "7491B3382FB4A3", + "de_type": 857 + }, + { + "contents": "28006920EB7BE921EE08CA9336FF3707D9EF2A7D46FD3CB35978CFCD0C72", + "de_type": 714 + } + ], + "encoded_section": "02E87E2FF9D4E8BED3A34DE8708A523395A9FDFF7E97F5E5222F1C4B3AA8AAF6845EA536945D4DFA8BFEDDC75C93B34610D1621CCE80013B78B90E0E007523EA372201FA31AFC18C88A789792AE6E37CC5F054D82642578AC1DAC9EC7A79931FAE1F296A85C216E879CB49D5438B4D9F7342F63576831F37CBA052BEF9674439", + "identity_token": "08ACA51C40D663F21A4CF2BFDAD1E502", + "key_seed": "D4B0FE67999329E23C3217DB7A469FC35280B5978CE80E532C08B59BCEE4EF00", + "nonce": "8FCF4745A019605307496CCF", + "section_mic_hmac_key": "E2CD200FD23CE0BCDB1CB503048CE71B4E7E3F150D5658F8234B6C6D28893749", + "section_salt": "E87E2FF9D4E8BED3A34DE8708A523395" + }, + { + "adv_header_byte": "20", + "aes_key": "5787FFD3CFFF8F69FE45E50872B49181", + "data_elements": [ + { + "contents": "8401AAFF665AD9920B6B33B839A72F", + "de_type": 237 + }, + { + "contents": "8B88158B1F60546E56508E86", + "de_type": 969 + } + ], + "encoded_section": "02E44ED613C98F0DC2AE5C4323042CD36D21B0A7C29E85FB08B05F62E9EA5FE3C231E9F3572CBD15F02D0A232F930664DE8A8D93CD63BF008526F7F60015C1BCB75F2BC2D12AC600CE2E0F87AA96C8E54BF99F", + "identity_token": "19D4435134937780CED35A279D095109", + "key_seed": "6C41D17E9C408D509BEC4EA6716F010BC72B801F9545BDF8F9DB9539AC6273C6", + "nonce": "189F567A1F62F04507652C14", + "section_mic_hmac_key": "D1B6432B61BB4272E325A6979882FE9BED562061A383C648C3294B19B707169C", + "section_salt": "E44ED613C98F0DC2AE5C4323042CD36D" + }, + { + "adv_header_byte": "20", + "aes_key": "5533BA11358651AC5301BCC7DFE8AC6E", + "data_elements": [ + { + "contents": "B775D5A14D08158FF431E168F10515145B07", + "de_type": 798 + }, + { + "contents": "2FE686DF80A9EBFE2405D84EAB72016B882AB50A11CE9EE5ECC5", + "de_type": 430 + }, + { + "contents": "1276D64D40BBAE244D398A82396342", + "de_type": 482 + }, + { + "contents": "C8EAFF62E466C78817A3747427C22E68750507B744A6", + "de_type": 823 + }, + { + "contents": "C964A89C33D058E2D533", + "de_type": 773 + } + ], + "encoded_section": "02A25AF6F97A49FD5AD7A58AC7C618CADCE311355595A5534B1F7F0BAADF291C8A7AB1895AF21700990CD60C3B451431E563A6D614CA7E04A84935698C0401CF79D74AA6DD6B65E23E6B0FDAA670D41B995EE23576190458B823A743CC915471252B601682AD93237C3B986070F377F4E1254953760337B10F55882E805E44447AE30E32DD4111B1BE46735F9409A8F57BFD89C9CBC8389EB5DC220B", + "identity_token": "F8378536329D2B2E962DE8AC894BA112", + "key_seed": "195197E02A7D9C2F04073A07987A7FBA10B4EAF66D69FAB54015A68960933535", + "nonce": "E3647946D8FC39BCBF6CB625", + "section_mic_hmac_key": "1E35AFE30548CE05848D3E362CD077E2DB826E10B217D21C3026CD2D91F1CAFC", + "section_salt": "A25AF6F97A49FD5AD7A58AC7C618CADC" + }, + { + "adv_header_byte": "20", + "aes_key": "E8EA3502A9010273177F4A0273E3B568", + "data_elements": [ + { + "contents": "", + "de_type": 93 + }, + { + "contents": "AD7FA1E4C83E494CADC0E105", + "de_type": 591 + }, + { + "contents": "8085D6", + "de_type": 425 + }, + { + "contents": "267DB04BA141F8A0B9D16F98F815AA051AC5A2DD18AE2CBB5C", + "de_type": 719 + }, + { + "contents": "0C4AD34F70D189FB9B6B93A52E0804BE81CAA18CDD", + "de_type": 272 + } + ], + "encoded_section": "025723B7208ADF96D9B8BC420F33486A6C8B36F43A0470FE4B458949F34055F1E75BAB75AA88F163CC5E6DCE56928779AB957A749284BD8B7B84527BF9AD52C4A08EF70D4CD2B76BAE77533DF9239474DCF758373A9D0EB08BD383A582626E70F39871439F29B764B9348F6B9984421D2E7F6A13C62B7164CC9219958E", + "identity_token": "655638465094190FE9A77463BFC9E126", + "key_seed": "AE9604009D3FD6E950A44CC767AE10C22A6744CCF2CD8E0C76E76385E6081DD5", + "nonce": "228A038D1F89336A39CD594D", + "section_mic_hmac_key": "ECB8CB36E3E179D9FD78006D46C85058F1A2BAB87014F58D792382331B7FC062", + "section_salt": "5723B7208ADF96D9B8BC420F33486A6C" + }, + { + "adv_header_byte": "20", + "aes_key": "489C9B6D1094A881909199D2F70129E9", + "data_elements": [ + { + "contents": "A50C355E004E703AB3E11199F9F7042FB8B297A8EF63EA692AE83EFCFD10", + "de_type": 636 + }, + { + "contents": "58069F92B86136E4DAFADE70D940D3C997D95F94", + "de_type": 434 + }, + { + "contents": "FE0781315E780B0C45D4B4B1", + "de_type": 577 + } + ], + "encoded_section": "0271B85F63AC3C61F03F39EF0E169D1D82FCF69C3E0CE5EE7830BAF677CAB9A146578963EA76613CC2A8B79EAD6AC940394D4BB937993A3C29BB3566FA8B23B9F6C035CDF9CA49FBAAF3B9D32E7D177EEE6D5E30D64DA436E0A6F3822B94C8F9DC84F77D0546A0728F6D4A0C0886DAE3C50D217601E697BB48", + "identity_token": "F795F354C5FEEBF98A35AA27BF4FB65D", + "key_seed": "9E41319F2ABE29937E2BC9AADB59DF37DDD64CC95470A1FA92FCD92284C49C07", + "nonce": "8D134D36CACDFA48AD2E1624", + "section_mic_hmac_key": "8F01AC5CEA8B33DC8E3A6917CACE845E3113D054A6F190CCA4F8B19B00789CCE", + "section_salt": "71B85F63AC3C61F03F39EF0E169D1D82" + }, + { + "adv_header_byte": "20", + "aes_key": "1AEFDBD92CF0BFDD813CED1AD930424B", + "data_elements": [ + { + "contents": "89", + "de_type": 537 + }, + { + "contents": "B5838F8BFF3E1FF8CBE34A", + "de_type": 148 + } + ], + "encoded_section": "02AD263B2C711BFC36EDFA522E9607CE18DA76E578E9130C9FEE33FEDA62BD179322CF68031C2EF90E092EDB3707CD7F86FA9CD806C56ABC93321E301D4986832966C748", + "identity_token": "03785872BE7F3F5A06BA8DE5A547A0B6", + "key_seed": "E3D6F78BC1A45CB75B06E63B81733A1B31DAF8AF1E4790B884599718BB790412", + "nonce": "67A8B67A65C9C4D46FCCDD11", + "section_mic_hmac_key": "6C89903E5DFF8B5D2CF1B2DE9EDDC78FAAC03B5EBCC77B9CF810A9F29E6AB15A", + "section_salt": "AD263B2C711BFC36EDFA522E9607CE18" + }, + { + "adv_header_byte": "20", + "aes_key": "11FEBEE577A641BE1BD6D7A95DA0DC61", + "data_elements": [], + "encoded_section": "029C0F1303B8D7E8FB226FC19EB2D987E443667F2221C7DAEF257221200FC24B6210F1D684DDAEE3DFA978FE9A0C807887B4", + "identity_token": "9BF79D0640C3F033616E88C085BA0E84", + "key_seed": "E71E5C9532BFF3AE23003A89003A6D78BCD3D11705FC47C56D55ACDF0C1E8625", + "nonce": "727CC259D161A356AEA07884", + "section_mic_hmac_key": "4D2C247CB47A94E69FB4D4BE132D0F7C3FFBC4756234ED5B1E6D3A8DB4A88F7A", + "section_salt": "9C0F1303B8D7E8FB226FC19EB2D987E4" + }, + { + "adv_header_byte": "20", + "aes_key": "72909F4BB264D9EE250C302AB93F9691", + "data_elements": [], + "encoded_section": "027BE514C8BD6C7BE897EA35578108DD35C1D8154719977EA32D96CA42E86AE207107F459409E5AAAA74A2DB0542D6062DEA", + "identity_token": "5846C49FD8AC98C1892ECFA87C40496D", + "key_seed": "8D6D511E1B70E96DCF325405832C77CC3565D1503AA3965894616C1F0C57E113", + "nonce": "1524A30566D6169A501F43C0", + "section_mic_hmac_key": "C743F000CE8B2ED5C3735E9CCEA37E634A0965E71CB8CE9DA599917FA6337C50", + "section_salt": "7BE514C8BD6C7BE897EA35578108DD35" + }, + { + "adv_header_byte": "20", + "aes_key": "9FCAF424921B3EAC6108BBAD5A73CB99", + "data_elements": [ + { + "contents": "9E1B5533A9E53934781C72", + "de_type": 208 + }, + { + "contents": "952B14BF77506C", + "de_type": 549 + }, + { + "contents": "6E5D3C18ACD4B106A55B4A2637FA57DCD34D", + "de_type": 782 + }, + { + "contents": "9931CB53B91C9EF8F62E358284A44B00D8AC1A95AA73", + "de_type": 222 + } + ], + "encoded_section": "02D14BDD76436FA2B760E9AF470F4321DDDA37CA2E790A42149020904EB4F7C88A560D3F833B34C52AFE8DF576F04DD03F9E961F946B06501E88B0D7EFCB951EB7D876BE437FE69385B7CF0F331CA1B3A2E3E95279F83E363542E7D5F757AE3091B5A288B485C50EF7BB755A39296357C1864AC797E35505", + "identity_token": "36D94D61F32E7B6B24F59C8295F1AF96", + "key_seed": "4BB6613384D29BA3C848795DD8C4A2C43DC9510A8EC03F6043E815AF783B7F38", + "nonce": "C59C14410DA46F23624443C5", + "section_mic_hmac_key": "DF3E0EA835945BC60C5F661AFE7A4E33A056508943126AC0D057BB51C453F71A", + "section_salt": "D14BDD76436FA2B760E9AF470F4321DD" + }, + { + "adv_header_byte": "20", + "aes_key": "CE880F0EE78F5EEF297475B681DFC310", + "data_elements": [ + { + "contents": "99F0EA", + "de_type": 289 + }, + { + "contents": "98F41B89B20F1FE7", + "de_type": 498 + }, + { + "contents": "467C", + "de_type": 91 + } + ], + "encoded_section": "02F18F6DCDBD4B8E8DE00A1A433A282C7EF840CA1A3788B4E9D8C8A6B9D413047925F0E300086648E857BB9ADFF9F6F6391661A854C2FA5F1AA7CA204D3DD126F6294C1E788D05", + "identity_token": "04ED862F43B938ABBCF539EBC70A59C7", + "key_seed": "710AE30C71188D8EB7E644A28219FF52966F449DC5B6BF342CC62A387E9FD166", + "nonce": "742EB407037A9A1001C248D7", + "section_mic_hmac_key": "49363E312316016C76C23E7AA07FB33C1CE4DBD0DDF9390FCA2601294E8740F0", + "section_salt": "F18F6DCDBD4B8E8DE00A1A433A282C7E" + } +] \ No newline at end of file
diff --git a/nearby/presence/np_adv/src/credential/book.rs b/nearby/presence/np_adv/src/credential/book.rs index 902d55a..ef6b269 100644 --- a/nearby/presence/np_adv/src/credential/book.rs +++ b/nearby/presence/np_adv/src/credential/book.rs
@@ -16,27 +16,25 @@ //! the credentials to try for either advertisement version. //! See [`CredentialBookBuilder`] for batteries-included implementations. -use crate::credential::source::{ - CredentialSource, DiscoveryCredentialSource, SliceCredentialSource, -}; -use crate::credential::v0::{V0DiscoveryCryptoMaterial, V0}; -use crate::credential::v1::{ - SignedSectionIdentityResolutionMaterial, SignedSectionVerificationMaterial, - UnsignedSectionIdentityResolutionMaterial, UnsignedSectionVerificationMaterial, - V1DiscoveryCryptoMaterial, V1, -}; -#[cfg(feature = "alloc")] -use crate::credential::ReferencedMatchedCredential; use crate::credential::{ - DiscoveryCryptoMaterial, MatchableCredential, MatchedCredential, ProtocolVersion, + source::{CredentialSource, SliceCredentialSource}, + v0::{V0DiscoveryCryptoMaterial, V0}, + v1::{ + MicExtendedSaltSectionIdentityResolutionMaterial, + MicExtendedSaltSectionVerificationMaterial, MicShortSaltSectionIdentityResolutionMaterial, + MicShortSaltSectionVerificationMaterial, SignedSectionIdentityResolutionMaterial, + SignedSectionVerificationMaterial, V1DiscoveryCryptoMaterial, V1, + }, + DiscoveryMetadataCryptoMaterial, MatchableCredential, MatchedCredential, ProtocolVersion, }; -use core::borrow::Borrow; -use core::marker::PhantomData; +use core::{borrow::Borrow, marker::PhantomData}; use crypto_provider::CryptoProvider; -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] extern crate alloc; -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] +use crate::credential::ReferencedMatchedCredential; +#[cfg(any(feature = "alloc", test))] use alloc::vec::Vec; /// A collection of credentials to try when attempting to deserialize @@ -171,17 +169,15 @@ /// refer to the "precalculated" crypto-material variants /// for each protocol version. pub(crate) mod precalculated_for_version { - use crate::credential::v0::{ - PrecalculatedV0DiscoveryCryptoMaterial, V0DiscoveryCredential, V0, + use crate::credential::{ + v0::{PrecalculatedV0DiscoveryCryptoMaterial, V0DiscoveryCredential, V0}, + v1::{PrecalculatedV1DiscoveryCryptoMaterial, V1DiscoveryCredential, V1}, + DiscoveryMetadataCryptoMaterial, ProtocolVersion, }; - use crate::credential::v1::{ - PrecalculatedV1DiscoveryCryptoMaterial, V1DiscoveryCredential, V1, - }; - use crate::credential::{DiscoveryCryptoMaterial, ProtocolVersion}; use crypto_provider::CryptoProvider; pub trait MappingTrait<V: ProtocolVersion> { - type Output: DiscoveryCryptoMaterial<V>; + type Output: DiscoveryMetadataCryptoMaterial<V>; /// Provides pre-calculated crypto-material for the given /// discovery credential. fn precalculate<C: CryptoProvider>( @@ -222,13 +218,12 @@ } /// Iterator type for [`CachedCredentialSource`]. -pub struct CachedCredentialSourceIterator< - 'a, - V: ProtocolVersion + 'a, - S: DiscoveryCredentialSource<'a, V> + 'a, - const N: usize, -> where +pub struct CachedCredentialSourceIterator<'a, V, S, const N: usize> +where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, + V: ProtocolVersion + 'a, + S: CredentialSource<'a, V> + 'a, + S::Crypto: Borrow<V::DiscoveryCredential>, { /// The current index of the (enumerated) elements that we're iterating over. /// Always counts up at every iteration, and may lie outside of the range @@ -244,10 +239,12 @@ source_iterator: S::Iterator, } -impl<'a, V: ProtocolVersion + 'a, S: DiscoveryCredentialSource<'a, V> + 'a, const N: usize> Iterator - for CachedCredentialSourceIterator<'a, V, S, N> +impl<'a, V, S, const N: usize> Iterator for CachedCredentialSourceIterator<'a, V, S, N> where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, + V: ProtocolVersion + 'a, + S: CredentialSource<'a, V> + 'a, + S::Crypto: Borrow<V::DiscoveryCredential>, { type Item = (PossiblyCachedDiscoveryCryptoMaterial<'a, V>, S::Matched); fn next(&mut self) -> Option<Self::Item> { @@ -272,7 +269,7 @@ } } -/// A [`CredentialSource`] which augments the externally-provided [`DiscoveryCredentialSource`] with +/// A [`CredentialSource`] which augments the externally-provided [`CredentialSource`] with /// a cache containing up to the specified number of pre-calculated credentials. pub struct CachedCredentialSource<V: ProtocolVersion, S, const N: usize> where @@ -292,7 +289,8 @@ original: &'a S, ) -> [Option<PrecalculatedCryptoForProtocolVersion<V>>; N] where - S: DiscoveryCredentialSource<'a, V> + 'a, + S: CredentialSource<'a, V> + 'a, + S::Crypto: Borrow<V::DiscoveryCredential>, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, { let mut cache = [0u8; N].map(|_| None); @@ -307,10 +305,10 @@ impl<'a, V: ProtocolVersion, S, const N: usize> CachedCredentialSource<V, S, N> where - S: DiscoveryCredentialSource<'a, V> + 'a, + S: CredentialSource<'a, V> + 'a, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, { - /// Constructs a [`CachedCredentialSource`] from the given [`DiscoveryCredentialSource`] + /// Constructs a [`CachedCredentialSource`] from the given [`CredentialSource`] /// and the given (initial) cache contents, as constructed via the /// [`init_cache_from_source`] helper function. pub(crate) fn new( @@ -354,7 +352,7 @@ } } -impl<'a, V: ProtocolVersion> DiscoveryCryptoMaterial<V> +impl<'a, V: ProtocolVersion> DiscoveryMetadataCryptoMaterial<V> for PossiblyCachedDiscoveryCryptoMaterial<'a, V> where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, @@ -368,7 +366,7 @@ } impl<'a> V0DiscoveryCryptoMaterial for PossiblyCachedDiscoveryCryptoMaterial<'a, V0> { - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C> { + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> { match &self.wrapped { PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => x.ldt_adv_cipher::<C>(), PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => x.ldt_adv_cipher::<C>(), @@ -390,15 +388,28 @@ } } - fn unsigned_identity_resolution_material<C: CryptoProvider>( + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial { + ) -> MicShortSaltSectionIdentityResolutionMaterial { match &self.wrapped { PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => { - x.unsigned_identity_resolution_material::<C>() + x.mic_short_salt_identity_resolution_material::<C>() } PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => { - x.unsigned_identity_resolution_material::<C>() + x.mic_short_salt_identity_resolution_material::<C>() + } + } + } + + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial { + match &self.wrapped { + PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => { + x.mic_extended_salt_identity_resolution_material::<C>() + } + PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => { + x.mic_extended_salt_identity_resolution_material::<C>() } } } @@ -414,15 +425,28 @@ } } - fn unsigned_verification_material<C: CryptoProvider>( + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial { + ) -> MicShortSaltSectionVerificationMaterial { match &self.wrapped { PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => { - x.unsigned_verification_material::<C>() + x.mic_short_salt_verification_material::<C>() } PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => { - x.unsigned_verification_material::<C>() + x.mic_short_salt_verification_material::<C>() + } + } + } + + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial { + match &self.wrapped { + PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => { + x.mic_extended_salt_verification_material::<C>() + } + PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => { + x.mic_extended_salt_verification_material::<C>() } } } @@ -432,11 +456,12 @@ for CachedCredentialSource<V, S, N> where Self: 'a, - S: DiscoveryCredentialSource<'a, V> + 'a, + S: CredentialSource<'a, V> + 'a, + S::Crypto: Borrow<V::DiscoveryCredential>, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, - PossiblyCachedDiscoveryCryptoMaterial<'a, V>: DiscoveryCryptoMaterial<V>, + PossiblyCachedDiscoveryCryptoMaterial<'a, V>: DiscoveryMetadataCryptoMaterial<V>, { - type Matched = <S as DiscoveryCredentialSource<'a, V>>::Matched; + type Matched = <S as CredentialSource<'a, V>>::Matched; type Crypto = PossiblyCachedDiscoveryCryptoMaterial<'a, V>; type Iterator = CachedCredentialSourceIterator<'a, V, S, N>; @@ -454,7 +479,7 @@ /// can store an arbitrary amount of pre-calculated crypto-materials. /// /// Requires `alloc` as a result of internally leveraging a `Vec`. -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] pub struct PrecalculatedOwnedCredentialSource<V: ProtocolVersion, M: MatchedCredential> where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, @@ -462,7 +487,7 @@ credentials: Vec<(PrecalculatedCryptoForProtocolVersion<V>, M)>, } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] impl<'a, V: ProtocolVersion + 'a, M: MatchedCredential + 'a> PrecalculatedOwnedCredentialSource<V, M> where @@ -486,7 +511,7 @@ } } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] fn reference_crypto_and_match_data<C, M: MatchedCredential>( pair_ref: &(C, M), ) -> (&C, ReferencedMatchedCredential<M>) { @@ -494,13 +519,13 @@ (c, m.into()) } -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] impl<'a, V: ProtocolVersion, M: MatchedCredential> CredentialSource<'a, V> for PrecalculatedOwnedCredentialSource<V, M> where Self: 'a, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>, - &'a PrecalculatedCryptoForProtocolVersion<V>: DiscoveryCryptoMaterial<V>, + &'a PrecalculatedCryptoForProtocolVersion<V>: DiscoveryMetadataCryptoMaterial<V>, { type Matched = ReferencedMatchedCredential<'a, M>; type Crypto = &'a PrecalculatedCryptoForProtocolVersion<V>; @@ -531,7 +556,7 @@ CachedSliceCredentialSource<'a, V1, M, N1>, >; -#[cfg(feature = "alloc")] +#[cfg(any(feature = "alloc", test))] /// A credential-book which owns all of its (non-matched) credential data, /// and maintains pre-calculated cryptographic information about all /// stored credentials for speedy advertisement deserialization.
diff --git a/nearby/presence/np_adv/src/credential/matched.rs b/nearby/presence/np_adv/src/credential/matched.rs new file mode 100644 index 0000000..90265d4 --- /dev/null +++ b/nearby/presence/np_adv/src/credential/matched.rs
@@ -0,0 +1,318 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains matched credential structs and traits which contain information about the credential +//! which is passed back to the caller upon a successful decrypt and credential match. + +#[cfg(any(test, feature = "alloc"))] +use alloc::vec::Vec; +#[cfg(any(test, feature = "alloc"))] +use crypto_provider::CryptoProvider; + +#[cfg(any(test, feature = "alloc"))] +use crate::credential::metadata::{decrypt_metadata_with_nonce, encrypt_metadata}; +use crate::credential::{v0::V0, v1::V1, ProtocolVersion}; +use core::{convert::Infallible, fmt::Debug}; +use ldt_np_adv::V0IdentityToken; + +/// The portion of a credential's data to be bundled with the advertisement content it was used to +/// decrypt. At a minimum, this includes any encrypted identity-specific metadata. +/// +/// As it is `Debug` and `Eq`, implementors should not hold any cryptographic secrets to avoid +/// accidental logging, timing side channels on comparison, etc, or should use custom impls of +/// those traits rather than deriving them. +/// +/// Instances of `MatchedCredential` may be cloned whenever advertisement content is +/// successfully associated with a credential (see [`WithMatchedCredential`]). As a +/// result, it's recommended to use matched-credentials which reference +/// some underlying match-data, but don't necessarily own it. +/// See [`ReferencedMatchedCredential`] for the most common case of shared references. +pub trait MatchedCredential: Debug + PartialEq + Eq + Clone { + /// The type returned for successful calls to [`Self::fetch_encrypted_metadata`]. + type EncryptedMetadata: AsRef<[u8]>; + + /// The type of errors for [`Self::fetch_encrypted_metadata`]. + type EncryptedMetadataFetchError: Debug; + + /// Attempts to obtain the (AES-GCM)-encrypted metadata bytes for the credential, + /// with possible failure based on the availability of the underlying data (i.e: + /// failing disk reads.) + /// + /// If your implementation does not maintain any encrypted metadata for each credential, + /// you may simply return an empty byte-array from this method. + /// + /// If your method for obtaining metadata cannot fail, use + /// the `core::convert::Infallible` type for the error type + /// [`Self::EncryptedMetadataFetchError`]. + fn fetch_encrypted_metadata( + &self, + ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError>; +} + +/// [`MatchedCredential`] wrapper around a shared reference to a [`MatchedCredential`]. +/// This is done instead of providing a blanket impl of [`MatchedCredential`] for +/// reference types to allow for downstream crates to impl [`MatchedCredential`] on +/// specific reference types. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ReferencedMatchedCredential<'a, M: MatchedCredential> { + wrapped: &'a M, +} + +impl<'a, M: MatchedCredential> From<&'a M> for ReferencedMatchedCredential<'a, M> { + fn from(wrapped: &'a M) -> Self { + Self { wrapped } + } +} + +impl<'a, M: MatchedCredential> AsRef<M> for ReferencedMatchedCredential<'a, M> { + fn as_ref(&self) -> &M { + self.wrapped + } +} + +impl<'a, M: MatchedCredential> MatchedCredential for ReferencedMatchedCredential<'a, M> { + type EncryptedMetadata = <M as MatchedCredential>::EncryptedMetadata; + type EncryptedMetadataFetchError = <M as MatchedCredential>::EncryptedMetadataFetchError; + fn fetch_encrypted_metadata( + &self, + ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { + self.wrapped.fetch_encrypted_metadata() + } +} + +/// A simple implementation of [`MatchedCredential`] where all match-data +/// is contained in the encrypted metadata byte-field. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MetadataMatchedCredential<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> { + encrypted_metadata: A, +} + +#[cfg(any(test, feature = "alloc"))] +impl MetadataMatchedCredential<Vec<u8>> { + /// Builds a [`MetadataMatchedCredential`] whose contents are given + /// as plaintext to be encrypted using AES-GCM against the given + /// broadcast crypto-material. + pub fn encrypt_from_plaintext<V, C>( + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + identity_token: V::IdentityToken, + plaintext_metadata: &[u8], + ) -> Self + where + V: ProtocolVersion, + C: CryptoProvider, + { + // TODO move this to identity provider + let encrypted_metadata = encrypt_metadata::<C, V>(hkdf, identity_token, plaintext_metadata); + Self { encrypted_metadata } + } +} + +impl<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> MetadataMatchedCredential<A> { + /// Builds a new [`MetadataMatchedCredential`] with the given + /// encrypted metadata. + pub fn new(encrypted_metadata: A) -> Self { + Self { encrypted_metadata } + } +} + +impl<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> MatchedCredential + for MetadataMatchedCredential<A> +{ + type EncryptedMetadata = A; + type EncryptedMetadataFetchError = Infallible; + fn fetch_encrypted_metadata(&self) -> Result<Self::EncryptedMetadata, Infallible> { + Ok(self.encrypted_metadata.clone()) + } +} + +/// Trivial implementation of [`MatchedCredential`] which consists of no match-data. +/// Suitable for usage scenarios where the decoded advertisement contents matter, +/// but not necessarily which devices generated the contents. +/// +/// Attempting to obtain the encrypted metadata from this type of credential +/// will always yield an empty byte-array. +#[derive(Default, Debug, PartialEq, Eq, Clone)] +pub struct EmptyMatchedCredential; + +impl MatchedCredential for EmptyMatchedCredential { + type EncryptedMetadata = [u8; 0]; + type EncryptedMetadataFetchError = Infallible; + fn fetch_encrypted_metadata( + &self, + ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { + Ok([0u8; 0]) + } +} + +#[cfg(any(test, feature = "devtools"))] +/// A [`MatchedCredential`] which consists only of the `key_seed` in the crypto-material +/// for the credential. Note that this is unique per-credential by construction, +/// and so this provides natural match-data for credentials in settings where +/// there may not be any other information available. +/// +/// Since this matched-credential type contains cryptographic information mirroring +/// a credential's crypto-material, this structure is not suitable for production +/// usage outside of unit tests and dev-tools. +/// +/// Additionally, note that the metadata on this particular kind of matched credential +/// is deliberately made inaccessible. This is done because a key-seed representation +/// is only suitable in very limited circumstances where no other meaningful +/// identifying information is available, such as that which is contained in metadata. +/// Attempting to obtain the encrypted metadata from this type of matched credential +/// will always yield an empty byte-array. +#[derive(Default, Debug, PartialEq, Eq, Clone)] +pub struct KeySeedMatchedCredential { + key_seed: [u8; 32], +} + +#[cfg(any(test, feature = "devtools"))] +impl From<[u8; 32]> for KeySeedMatchedCredential { + fn from(key_seed: [u8; 32]) -> Self { + Self { key_seed } + } +} +#[cfg(any(test, feature = "devtools"))] +impl From<KeySeedMatchedCredential> for [u8; 32] { + fn from(matched: KeySeedMatchedCredential) -> Self { + matched.key_seed + } +} + +#[cfg(any(test, feature = "devtools"))] +impl MatchedCredential for KeySeedMatchedCredential { + type EncryptedMetadata = [u8; 0]; + type EncryptedMetadataFetchError = Infallible; + fn fetch_encrypted_metadata( + &self, + ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { + Ok([0u8; 0]) + } +} + +/// Common trait to deserialized, decrypted V0 advs and V1 sections which +/// exposes relevant data about matched identities. +pub trait HasIdentityMatch { + /// The protocol version for which this advertisement + /// content has an identity-match. + type Version: ProtocolVersion; + + /// Gets the decrypted plaintext version-specific + /// metadata key for the associated identity. + fn identity_token(&self) -> <Self::Version as ProtocolVersion>::IdentityToken; +} + +impl HasIdentityMatch for V0IdentityToken { + type Version = V0; + fn identity_token(&self) -> Self { + *self + } +} + +impl HasIdentityMatch for crate::extended::V1IdentityToken { + type Version = V1; + fn identity_token(&self) -> Self { + *self + } +} + +#[cfg(any(test, feature = "alloc"))] +/// Type for errors from [`WithMatchedCredential#decrypt_metadata`] +#[derive(Debug)] +pub enum MatchedMetadataDecryptionError<M: MatchedCredential> { + /// Retrieving the encrypted metadata failed for one reason + /// or another, so we didn't get a chance to try decryption. + RetrievalFailed(<M as MatchedCredential>::EncryptedMetadataFetchError), + /// The encrypted metadata could be retrieved, but it did + /// not successfully decrypt against the matched identity. + /// This could be an indication of data corruption or + /// of malformed crypto on the sender-side. + DecryptionFailed, +} + +/// Decrypted advertisement content with the [MatchedCredential] from the credential that decrypted +/// it, along with any other information which is relevant to the identity-match. +#[derive(Debug, PartialEq, Eq)] +pub struct WithMatchedCredential<M: MatchedCredential, T: HasIdentityMatch> { + matched: M, + /// The 12-byte metadata nonce as derived from the key-seed HKDF + /// to be used for decrypting the encrypted metadata in the attached + /// matched-credential. + metadata_nonce: [u8; 12], + contents: T, +} + +impl<'a, M: MatchedCredential + Clone, T: HasIdentityMatch> + WithMatchedCredential<ReferencedMatchedCredential<'a, M>, T> +{ + /// Clones the referenced match-data to update this container + /// so that the match-data is owned, rather than borrowed. + pub fn clone_match_data(self) -> WithMatchedCredential<M, T> { + let matched = self.matched.as_ref().clone(); + let metadata_nonce = self.metadata_nonce; + let contents = self.contents; + + WithMatchedCredential { matched, metadata_nonce, contents } + } +} + +impl<M: MatchedCredential, T: HasIdentityMatch> WithMatchedCredential<M, T> { + pub(crate) fn new(matched: M, metadata_nonce: [u8; 12], contents: T) -> Self { + Self { matched, metadata_nonce, contents } + } + /// Applies the given function to the wrapped contents, yielding + /// a new instance with the same matched-credential. + pub fn map<R: HasIdentityMatch>( + self, + mapping: impl FnOnce(T) -> R, + ) -> WithMatchedCredential<M, R> { + let contents = mapping(self.contents); + let matched = self.matched; + let metadata_nonce = self.metadata_nonce; + WithMatchedCredential { matched, metadata_nonce, contents } + } + /// Credential data for the credential that decrypted the content. + pub fn matched_credential(&self) -> &M { + &self.matched + } + /// The decrypted advertisement content. + pub fn contents(&self) -> &T { + &self.contents + } + + #[cfg(any(test, feature = "alloc"))] + fn decrypt_metadata_from_fetch<C: CryptoProvider>( + &self, + encrypted_metadata: &[u8], + ) -> Result<Vec<u8>, MatchedMetadataDecryptionError<M>> { + decrypt_metadata_with_nonce::<C, T::Version>( + self.metadata_nonce, + self.contents.identity_token(), + encrypted_metadata, + ) + .map_err(|_| MatchedMetadataDecryptionError::DecryptionFailed) + } + + #[cfg(any(test, feature = "alloc"))] + /// Attempts to decrypt the encrypted metadata + /// associated with the matched credential + /// based on the details of the identity-match. + pub fn decrypt_metadata<C: CryptoProvider>( + &self, + ) -> Result<Vec<u8>, MatchedMetadataDecryptionError<M>> { + self.matched + .fetch_encrypted_metadata() + .map_err(|e| MatchedMetadataDecryptionError::RetrievalFailed(e)) + .and_then(|x| Self::decrypt_metadata_from_fetch::<C>(self, x.as_ref())) + } +}
diff --git a/nearby/presence/np_adv/src/credential/metadata/mod.rs b/nearby/presence/np_adv/src/credential/metadata/mod.rs new file mode 100644 index 0000000..4e3a930 --- /dev/null +++ b/nearby/presence/np_adv/src/credential/metadata/mod.rs
@@ -0,0 +1,79 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A parking ground for the semi-dormant metadata code. +//! +//! Eventually, when we have a clearer idea of how metadat encryption and identity providers +//! interact, this is likely to change aggressively. + +use alloc::vec::Vec; +use crypto_provider::{ + aead::{Aead, AeadInit}, + aes::{self}, + CryptoProvider, +}; + +use crate::credential::{MetadataDecryptionError, ProtocolVersion}; + +#[cfg(test)] +mod tests; + +/// Encrypts the given plaintext metadata bytes to allow that metadata +/// to be shared with receiving devices. +pub fn encrypt_metadata<C: CryptoProvider, V: ProtocolVersion>( + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + identity_token: V::IdentityToken, + plaintext_metadata: &[u8], +) -> Vec<u8> { + let aead = <<C as CryptoProvider>::Aes128Gcm as AeadInit<aes::Aes128Key>>::new( + &V::extract_metadata_key::<C>(identity_token), + ); + // No additional authenticated data for encrypted metadata. + aead.encrypt(plaintext_metadata, &[], &V::metadata_nonce_from_key_seed(hkdf)) + .expect("Metadata encryption should be infallible") +} + +/// Decrypt the given metadata using the given hkdf and version-specific +/// identity token. Returns [`MetadataDecryptionError`] in the case that +/// the decryption operation failed. +/// +/// See also [decrypt_metadata_with_nonce]. +pub fn decrypt_metadata<C: CryptoProvider, V: ProtocolVersion>( + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + identity_token: V::IdentityToken, + encrypted_metadata: &[u8], +) -> Result<Vec<u8>, MetadataDecryptionError> { + decrypt_metadata_with_nonce::<C, V>( + V::metadata_nonce_from_key_seed(hkdf), + identity_token, + encrypted_metadata, + ) +} + +/// Decrypt the given metadata using the given hkdf and version-specific +/// identity token. Returns [`MetadataDecryptionError`] in the case that +/// the decryption operation failed. +/// +/// See also [decrypt_metadata]. +pub fn decrypt_metadata_with_nonce<C: CryptoProvider, V: ProtocolVersion>( + nonce: <C::Aes128Gcm as Aead>::Nonce, + identity_token: V::IdentityToken, + encrypted_metadata: &[u8], +) -> Result<Vec<u8>, MetadataDecryptionError> { + // No additional authenticated data for encrypted metadata. + let metadata_key = V::extract_metadata_key::<C>(identity_token); + <<C as CryptoProvider>::Aes128Gcm as AeadInit<aes::Aes128Key>>::new(&metadata_key) + .decrypt(encrypted_metadata, &[], &nonce) + .map_err(|_| MetadataDecryptionError) +}
diff --git a/nearby/presence/np_adv/src/credential/metadata/tests.rs b/nearby/presence/np_adv/src/credential/metadata/tests.rs new file mode 100644 index 0000000..0409ebf --- /dev/null +++ b/nearby/presence/np_adv/src/credential/metadata/tests.rs
@@ -0,0 +1,95 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::credential::v0::V0; +use crate::credential::v1::V1; +use crate::extended::V1IdentityToken; +use alloc::vec; +use crypto_provider_default::CryptoProviderImpl; +use ldt_np_adv::V0IdentityToken; + +#[test] +fn v0_metadata_decryption_works_same_metadata_key() { + let key_seed = [3u8; 32]; + let identity_token = V0IdentityToken::from([5u8; 14]); + + let metadata = vec![7u8; 42]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let encrypted_metadata = + encrypt_metadata::<CryptoProviderImpl, V0>(&hkdf, identity_token, &metadata); + + let decryption_result = + decrypt_metadata::<CryptoProviderImpl, V0>(&hkdf, identity_token, &encrypted_metadata); + assert_eq!(decryption_result, Ok(metadata)) +} + +#[test] +fn v1_metadata_decryption_works_same_metadata_key() { + let key_seed = [9u8; 32]; + let identity_token = V1IdentityToken::from([2u8; 16]); + + let metadata = vec![6u8; 51]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let encrypted_metadata = + encrypt_metadata::<CryptoProviderImpl, V1>(&hkdf, identity_token, &metadata); + + let decryption_result = + decrypt_metadata::<CryptoProviderImpl, V1>(&hkdf, identity_token, &encrypted_metadata); + assert_eq!(decryption_result, Ok(metadata)) +} + +#[test] +fn v0_metadata_decryption_fails_different_metadata_key() { + let key_seed = [3u8; 32]; + let identity_token = V0IdentityToken::from([5u8; 14]); + + let metadata = vec![7u8; 42]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let encrypted_metadata = + encrypt_metadata::<CryptoProviderImpl, V0>(&hkdf, identity_token, &metadata); + + let decrypting_identity_token = V0IdentityToken::from([6u8; 14]); + + let decryption_result = decrypt_metadata::<CryptoProviderImpl, V0>( + &hkdf, + decrypting_identity_token, + &encrypted_metadata, + ); + assert_eq!(decryption_result, Err(MetadataDecryptionError)) +} + +#[test] +fn v1_metadata_decryption_fails_different_metadata_key() { + let key_seed = [251u8; 32]; + let identity_token = V1IdentityToken::from([127u8; 16]); + + let metadata = vec![255u8; 42]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let encrypted_metadata = + encrypt_metadata::<CryptoProviderImpl, V1>(&hkdf, identity_token, &metadata); + + let decrypting_identity_token = V1IdentityToken::from([249u8; 16]); + + let decryption_result = decrypt_metadata::<CryptoProviderImpl, V1>( + &hkdf, + decrypting_identity_token, + &encrypted_metadata, + ); + assert_eq!(decryption_result, Err(MetadataDecryptionError)) +}
diff --git a/nearby/presence/np_adv/src/credential/mod.rs b/nearby/presence/np_adv/src/credential/mod.rs index 3cab51e..b61106d 100644 --- a/nearby/presence/np_adv/src/credential/mod.rs +++ b/nearby/presence/np_adv/src/credential/mod.rs
@@ -18,25 +18,25 @@ //! efficiency gains with implementations tailored to suit (e.g. caching a few hot credentials //! rather than reading from disk every time, etc). -use crate::MetadataKey; - -use crate::credential::v0::{V0DiscoveryCredential, V0ProtocolVersion}; - -use core::convert::Infallible; +use crate::credential::matched::{MatchedCredential, ReferencedMatchedCredential}; use core::fmt::Debug; -use crypto_provider::{CryptoProvider, CryptoRng}; +use crypto_provider::{aead::Aead, aes, CryptoProvider, FromCryptoRng}; pub mod book; +pub mod matched; pub mod source; -#[cfg(test)] -pub mod tests; pub mod v0; pub mod v1; +#[cfg(any(test, feature = "alloc"))] +pub mod metadata; + +#[cfg(test)] +mod tests; + /// Information about a credential as supplied by the caller. -#[derive(Clone)] pub struct MatchableCredential<V: ProtocolVersion, M: MatchedCredential> { - /// The discovery credential/cryptographic information associated + /// The cryptographic information associated /// with this particular credential which is used for discovering /// advertisements/advertisement sections generated via the /// paired sender credential. @@ -47,11 +47,6 @@ } impl<V: ProtocolVersion, M: MatchedCredential> MatchableCredential<V, M> { - /// De-structures this credential into the pairing of a discovery - /// credential and some matched credential data. - pub fn into_pair(self) -> (V::DiscoveryCredential, M) { - (self.discovery_credential, self.match_data) - } /// Views this credential as a (borrowed) discovery-credential /// combined with some matched credential data /// (which is copied - see documentation on [`MatchedCredential`]) @@ -60,176 +55,6 @@ } } -/// The portion of a credential's data to be bundled with the advertisement content it was used to -/// decrypt. At a minimum, this includes any encrypted identity-specific metadata. -/// -/// As it is `Debug` and `Eq`, implementors should not hold any cryptographic secrets to avoid -/// accidental logging, timing side channels on comparison, etc, or should use custom impls of -/// those traits rather than deriving them. -/// -/// Instances of `MatchedCredential` may be cloned whenever advertisement content is -/// successfully associated with a credential (see [`crate::WithMatchedCredential`]). As a -/// result, it's recommended to use matched-credentials which reference -/// some underlying match-data, but don't necessarily own it. -/// See [`ReferencedMatchedCredential`] for the most common case of shared references. -pub trait MatchedCredential: Debug + PartialEq + Eq + Clone { - /// The type returned for successful calls to [`Self::fetch_encrypted_metadata`]. - type EncryptedMetadata: AsRef<[u8]>; - - /// The type of errors for [`Self::fetch_encrypted_metadata`]. - type EncryptedMetadataFetchError: Debug; - - /// Attempts to obtain the (AES-GCM)-encrypted metadata bytes for the credential, - /// with possible failure based on the availability of the underlying data (i.e: - /// failing disk reads.) - /// - /// If your implementation does not maintain any encrypted metadata for each credential, - /// you may simply return an empty byte-array from this method. - /// - /// If your method for obtaining metadata cannot fail, use - /// the `core::convert::Infallible` type for the error type - /// [`Self::EncryptedMetadataFetchError`]. - fn fetch_encrypted_metadata( - &self, - ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError>; -} - -/// [`MatchedCredential`] wrapper around a shared reference to a [`MatchedCredential`]. -/// This is done instead of providing a blanket impl of [`MatchedCredential`] for -/// reference types to allow for downstream crates to impl [`MatchedCredential`] on -/// specific reference types. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ReferencedMatchedCredential<'a, M: MatchedCredential> { - wrapped: &'a M, -} - -impl<'a, M: MatchedCredential> From<&'a M> for ReferencedMatchedCredential<'a, M> { - fn from(wrapped: &'a M) -> Self { - Self { wrapped } - } -} - -impl<'a, M: MatchedCredential> AsRef<M> for ReferencedMatchedCredential<'a, M> { - fn as_ref(&self) -> &M { - self.wrapped - } -} - -impl<'a, M: MatchedCredential> MatchedCredential for ReferencedMatchedCredential<'a, M> { - type EncryptedMetadata = <M as MatchedCredential>::EncryptedMetadata; - type EncryptedMetadataFetchError = <M as MatchedCredential>::EncryptedMetadataFetchError; - fn fetch_encrypted_metadata( - &self, - ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { - self.wrapped.fetch_encrypted_metadata() - } -} - -/// A simple implementation of [`MatchedCredential`] where all match-data -/// is contained in the encrypted metadata byte-field. -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct MetadataMatchedCredential<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> { - encrypted_metadata: A, -} - -#[cfg(any(test, feature = "alloc"))] -impl MetadataMatchedCredential<alloc::vec::Vec<u8>> { - /// Builds a [`MetadataMatchedCredential`] whose contents are given - /// as plaintext to be encrypted using AES-GCM against the given - /// broadcast crypto-material. - pub fn encrypt_from_plaintext<V, B, C>(broadcast_cm: &B, plaintext_metadata: &[u8]) -> Self - where - V: ProtocolVersion, - B: BroadcastCryptoMaterial<V>, - C: CryptoProvider, - { - let encrypted_metadata = broadcast_cm.encrypt_metadata::<C>(plaintext_metadata); - Self { encrypted_metadata } - } -} - -impl<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> MetadataMatchedCredential<A> { - /// Builds a new [`MetadataMatchedCredential`] with the given - /// encrypted metadata. - pub fn new(encrypted_metadata: A) -> Self { - Self { encrypted_metadata } - } -} - -impl<A: AsRef<[u8]> + Clone + Debug + PartialEq + Eq> MatchedCredential - for MetadataMatchedCredential<A> -{ - type EncryptedMetadata = A; - type EncryptedMetadataFetchError = Infallible; - fn fetch_encrypted_metadata(&self) -> Result<Self::EncryptedMetadata, Infallible> { - Ok(self.encrypted_metadata.clone()) - } -} - -/// Trivial implementation of [`MatchedCredential`] which consists of no match-data. -/// Suitable for usage scenarios where the decoded advertisement contents matter, -/// but not necessarily which devices generated the contents. -/// -/// Attempting to obtain the encrypted metadata from this type of credential -/// will always yield an empty byte-array. -#[derive(Default, Debug, PartialEq, Eq, Clone)] -pub struct EmptyMatchedCredential; - -impl MatchedCredential for EmptyMatchedCredential { - type EncryptedMetadata = [u8; 0]; - type EncryptedMetadataFetchError = Infallible; - fn fetch_encrypted_metadata( - &self, - ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { - Ok([0u8; 0]) - } -} - -#[cfg(any(test, feature = "devtools"))] -/// A [`MatchedCredential`] which consists only of the `key_seed` in the crypto-material -/// for the credential. Note that this is unique per-credential by construction, -/// and so this provides natural match-data for credentials in settings where -/// there may not be any other information available. -/// -/// Since this matched-credential type contains cryptographic information mirroring -/// a credential's crypto-material, this structure is not suitable for production -/// usage outside of unit tests and dev-tools. -/// -/// Additionally, note that the metadata on this particular kind of matched credential -/// is deliberately made inaccessible. This is done because a key-seed representation -/// is only suitable in very limited circumstances where no other meaningful -/// identifying information is available, such as that which is contained in metadata. -/// Attempting to obtain the encrypted metadata from this type of matched credential -/// will always yield an empty byte-array. -#[derive(Default, Debug, PartialEq, Eq, Clone)] -pub struct KeySeedMatchedCredential { - key_seed: [u8; 32], -} - -#[cfg(any(test, feature = "devtools"))] -impl From<[u8; 32]> for KeySeedMatchedCredential { - fn from(key_seed: [u8; 32]) -> Self { - Self { key_seed } - } -} -#[cfg(any(test, feature = "devtools"))] -impl From<KeySeedMatchedCredential> for [u8; 32] { - fn from(matched: KeySeedMatchedCredential) -> Self { - matched.key_seed - } -} - -#[cfg(any(test, feature = "devtools"))] -impl MatchedCredential for KeySeedMatchedCredential { - type EncryptedMetadata = [u8; 0]; - type EncryptedMetadataFetchError = Infallible; - fn fetch_encrypted_metadata( - &self, - ) -> Result<Self::EncryptedMetadata, Self::EncryptedMetadataFetchError> { - Ok([0u8; 0]) - } -} - /// Error returned when metadata decryption fails. #[derive(Debug, Eq, PartialEq)] pub struct MetadataDecryptionError; @@ -248,43 +73,24 @@ /// is the minimal amount of cryptographic materials that we need /// in order to discover advertisements/sections which make /// use of the sender-paired version of the credential. - type DiscoveryCredential: DiscoveryCryptoMaterial<Self> + Clone; + type DiscoveryCredential: DiscoveryMetadataCryptoMaterial<Self> + Clone; - /// The native-length metadata key for this protocol version - /// [i.e: if V0, a 14-byte metadata key, or if V1, a 16-byte - /// metadata key.] - type MetadataKey: Clone + AsRef<[u8]>; + /// The native-length identity token for this protocol version + /// [i.e: if V0, a 14-byte identity token, or if V1, a 16-byte + /// identity token.] + type IdentityToken: Clone + AsRef<[u8]> + FromCryptoRng; /// Computes the metadata nonce for this version from the given key-seed. - fn metadata_nonce_from_key_seed<C: CryptoProvider>(key_seed: &[u8; 32]) -> [u8; 12]; + fn metadata_nonce_from_key_seed<C: CryptoProvider>( + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> <C::Aes128Gcm as Aead>::Nonce; - /// Expands the passed metadata key (if needed) to a 16-byte metadata key + // TODO this should be done by the identity provider that owns the corresponding credential + /// Transforms the passed metadata key (if needed) to a 16-byte metadata key /// which may be used for metadata encryption/decryption - fn expand_metadata_key<C: CryptoProvider>(metadata_key: Self::MetadataKey) -> MetadataKey; - - /// Generates a random metadata key using the given cryptographically-secure Rng - fn gen_random_metadata_key<R: CryptoRng>(rng: &mut R) -> Self::MetadataKey; - - #[cfg(any(test, feature = "alloc"))] - /// Decrypt the given metadata using the given metadata nonce and version-specific - /// metadata key. Returns [`MetadataDecryptionError`] in the case that - /// the decryption operation failed. - fn decrypt_metadata<C: CryptoProvider>( - metadata_nonce: [u8; 12], - metadata_key: Self::MetadataKey, - encrypted_metadata: &[u8], - ) -> Result<alloc::vec::Vec<u8>, MetadataDecryptionError> { - use crypto_provider::{ - aead::{Aead, AeadInit}, - aes::Aes128Key, - }; - - let metadata_key = Self::expand_metadata_key::<C>(metadata_key); - let metadata_key = Aes128Key::from(metadata_key.0); - let aead = <<C as CryptoProvider>::Aes128Gcm as AeadInit<Aes128Key>>::new(&metadata_key); - // No additional authenticated data for encrypted metadata. - aead.decrypt(encrypted_metadata, &[], &metadata_nonce).map_err(|_| MetadataDecryptionError) - } + fn extract_metadata_key<C: CryptoProvider>( + identity_token: Self::IdentityToken, + ) -> aes::Aes128Key; } /// Trait for structures which provide cryptographic @@ -292,101 +98,8 @@ /// See [`crate::credential::v0::V0DiscoveryCryptoMaterial`] /// and [`crate::credential::v1::V1DiscoveryCryptoMaterial`] /// for V0 and V1 specializations. -pub trait DiscoveryCryptoMaterial<V: ProtocolVersion> { +pub trait DiscoveryMetadataCryptoMaterial<V: ProtocolVersion> { /// Constructs or copies the metadata nonce used for decryption of associated credential /// metadata for the identity represented via this crypto material. fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12]; } - -/// Cryptographic materials necessary for broadcasting encrypted -/// advertisement contents with the given protocol version. -pub trait BroadcastCryptoMaterial<V: ProtocolVersion> { - /// Yields a copy of the key seed to be used to derive other key materials used - /// in the encryption of broadcasted advertisement contents. - fn key_seed(&self) -> [u8; 32]; - - /// Yields a copy of the metadata-key (size dependent on protocol version) - /// to tag advertisement contents sent with this broadcast crypto-material. - fn metadata_key(&self) -> V::MetadataKey; - - /// Yields the 16-byte expanded metadata key, suitable for metadata encryption. - fn expanded_metadata_key<C: CryptoProvider>(&self) -> MetadataKey { - V::expand_metadata_key::<C>(self.metadata_key()) - } - - /// Constructs the metadata nonce used for encryption of associated credential - /// metadata for the identity represented via this crypto material. - fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { - V::metadata_nonce_from_key_seed::<C>(&self.key_seed()) - } - - /// Derives a V0 discovery credential from this V0 broadcast crypto-material - /// which may be used to discover v0 advertisements broadcasted with this credential.` - fn derive_v0_discovery_credential<C: CryptoProvider>(&self) -> V0DiscoveryCredential - where - V: V0ProtocolVersion, - { - let key_seed = self.key_seed(); - let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); - let metadata_key_hmac = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(self.metadata_key().as_ref()); - V0DiscoveryCredential::new(key_seed, metadata_key_hmac) - } - - #[cfg(any(test, feature = "alloc"))] - /// Encrypts the given plaintext metadata bytes to allow that metadata - /// to be shared with receiving devices. - fn encrypt_metadata<C: CryptoProvider>( - &self, - plaintext_metadata: &[u8], - ) -> alloc::vec::Vec<u8> { - use crypto_provider::{ - aead::{Aead, AeadInit}, - aes::Aes128Key, - }; - let plaintext_metadata_key = self.expanded_metadata_key::<C>(); - let plaintext_metadata_key = Aes128Key::from(plaintext_metadata_key.0); - - let aead = - <<C as CryptoProvider>::Aes128Gcm as AeadInit<Aes128Key>>::new(&plaintext_metadata_key); - // No additional authenticated data for encrypted metadata. - aead.encrypt(plaintext_metadata, &[], &self.metadata_nonce::<C>()) - .expect("Metadata encryption should be infallible") - } -} - -/// Concrete implementation of [`BroadcastCryptoMaterial<V>`] for -/// a particular protocol version which keeps the key seed -/// and the metadata key contiguous in memory. -/// -/// Broadcast crypto-material specified in this way will only -/// be usable for (unsigned) advertisement content broadcasts -/// in the given protocol version. -/// -/// For more flexible expression of broadcast credentials, -/// feel free to directly implement one or more of the -/// [`BroadcastCryptoMaterial`] and/or -/// [`crate::credential::v1::SignedBroadcastCryptoMaterial`] -/// traits on your own struct, dependent on the details -/// of your own broadcast credentials. -pub struct SimpleBroadcastCryptoMaterial<V: ProtocolVersion> { - key_seed: [u8; 32], - metadata_key: V::MetadataKey, -} - -impl<V: ProtocolVersion> SimpleBroadcastCryptoMaterial<V> { - /// Builds some simple broadcast crypto-materials out of - /// the provided key-seed and version-specific metadata-key. - pub fn new(key_seed: [u8; 32], metadata_key: V::MetadataKey) -> Self { - Self { key_seed, metadata_key } - } -} - -impl<V: ProtocolVersion> BroadcastCryptoMaterial<V> for SimpleBroadcastCryptoMaterial<V> { - fn key_seed(&self) -> [u8; 32] { - self.key_seed - } - fn metadata_key(&self) -> V::MetadataKey { - self.metadata_key.clone() - } -}
diff --git a/nearby/presence/np_adv/src/credential/source.rs b/nearby/presence/np_adv/src/credential/source.rs index 709bbd6..f22ed97 100644 --- a/nearby/presence/np_adv/src/credential/source.rs +++ b/nearby/presence/np_adv/src/credential/source.rs
@@ -16,59 +16,17 @@ //! credentials for discovering advertisements/advertisement //! sections for a _particular_ protocol version. -use crate::credential::{ - DiscoveryCryptoMaterial, MatchableCredential, MatchedCredential, ProtocolVersion, - ReferencedMatchedCredential, -}; -use core::borrow::Borrow; - -/// Specialized version of the [`CredentialSource`] trait for -/// credential-sources which provide discovery credentials -/// for a specific protocol version. -/// -/// If you want ready-made structures which can provide -/// credentials for both V0 and V1 protocol versions, -/// see [`crate::credential::book::CredentialBook`] -/// and [`crate::credential::book::CredentialBookBuilder`] instead. -/// -/// It's preferred to use this kind of credential-source -/// in client code, if possible, and then lift to a -/// [`CredentialSource`] using [`AsCredentialSource`] -/// instead of implementing [`CredentialSource`] directly, -/// since it's better to trust this crate to handle -/// the details of what's in [`DiscoveryCryptoMaterial`]s -/// for specific protocol versions. -pub trait DiscoveryCredentialSource<'a, V: ProtocolVersion> -where - Self: 'a, -{ - /// The kind of data yielded to the caller upon a successful - /// identity-match. - type Matched: MatchedCredential; - - /// The kind of crypto-material yielded from the wrapped - /// iterator, which allows borrowing a discovery credential. - type Crypto: DiscoveryCryptoMaterial<V> + Borrow<V::DiscoveryCredential>; - - /// The iterator type produced which emits credentials. - /// This is a lending iterator which may borrow things from `self`. - type Iterator: Iterator<Item = (Self::Crypto, Self::Matched)>; - - /// Iterate over the available credentials - fn iter(&'a self) -> Self::Iterator; -} +use crate::credential::matched::{MatchedCredential, ReferencedMatchedCredential}; +use crate::credential::{DiscoveryMetadataCryptoMaterial, MatchableCredential, ProtocolVersion}; /// A source of credentials for a particular protocol version, -/// utilizing any [`DiscoveryCryptoMaterial`] which is usable +/// utilizing any [`DiscoveryMetadataCryptoMaterial`] which is usable /// for discovering advertisements in that protocol version. /// /// This trait is largely leveraged as a tool for building /// new kinds of [`crate::credential::book::CredentialBook`]s /// via the [`crate::credential::book::CredentialBookFromSources`] -/// wrapper. It differs from the [`DiscoveryCredentialSource`] -/// trait in that the crypto-materials do not have to be -/// discovery credentials, and can instead be some pre-calculated -/// crypto-materials. +/// wrapper. /// /// See [`crate::credential::book::CachedCredentialSource`] /// for an example of this pattern. @@ -82,7 +40,7 @@ /// The kind of crypto-material yielded from the wrapped /// iterator. - type Crypto: DiscoveryCryptoMaterial<V>; + type Crypto: DiscoveryMetadataCryptoMaterial<V>; /// The iterator type produced which emits credentials. /// This is a lending iterator which may borrow things from `self`. @@ -92,27 +50,7 @@ fn iter(&'a self) -> Self::Iterator; } -// Note: This is needed to get around coherence problems -// with the [`CredentialSource`] trait's relationship -// with [`DiscoveryCredentialSource`] if it were declared -// as a sub-trait (i.e: conflicting impls) -/// Wrapper which turns any [`DiscoveryCredentialSource`] -/// into a [`CredentialSource`]. -pub struct AsCredentialSource<S>(pub S); - -impl<'a, V: ProtocolVersion, S: DiscoveryCredentialSource<'a, V>> CredentialSource<'a, V> - for AsCredentialSource<S> -{ - type Matched = <S as DiscoveryCredentialSource<'a, V>>::Matched; - type Crypto = <S as DiscoveryCredentialSource<'a, V>>::Crypto; - type Iterator = <S as DiscoveryCredentialSource<'a, V>>::Iterator; - - fn iter(&'a self) -> Self::Iterator { - self.0.iter() - } -} - -/// A simple [`DiscoveryCredentialSource`] which iterates over a provided slice of credentials +/// A simple [`CredentialSource`] which iterates over a provided slice of credentials pub struct SliceCredentialSource<'c, V: ProtocolVersion, M: MatchedCredential> { credentials: &'c [MatchableCredential<V, M>], } @@ -124,12 +62,12 @@ } } -impl<'a, 'b, V: ProtocolVersion, M: MatchedCredential> DiscoveryCredentialSource<'a, V> +impl<'a, 'b, V: ProtocolVersion, M: MatchedCredential> CredentialSource<'a, V> for SliceCredentialSource<'b, V, M> where 'b: 'a, Self: 'b, - &'a <V as ProtocolVersion>::DiscoveryCredential: DiscoveryCryptoMaterial<V>, + &'a <V as ProtocolVersion>::DiscoveryCredential: DiscoveryMetadataCryptoMaterial<V>, { type Matched = ReferencedMatchedCredential<'a, M>; type Crypto = &'a V::DiscoveryCredential;
diff --git a/nearby/presence/np_adv/src/credential/tests.rs b/nearby/presence/np_adv/src/credential/tests.rs index 8b12bfc..7e92934 100644 --- a/nearby/presence/np_adv/src/credential/tests.rs +++ b/nearby/presence/np_adv/src/credential/tests.rs
@@ -15,38 +15,38 @@ extern crate alloc; +use crate::credential::matched::{ + EmptyMatchedCredential, KeySeedMatchedCredential, ReferencedMatchedCredential, +}; +use crate::credential::v1::MicSectionVerificationMaterial; use crate::credential::{ book::{ init_cache_from_source, CachedCredentialSource, PossiblyCachedDiscoveryCryptoMaterialKind, }, source::{CredentialSource, SliceCredentialSource}, v0::{V0DiscoveryCredential, V0}, - v1::{ - SignedBroadcastCryptoMaterial, SimpleSignedBroadcastCryptoMaterial, V1DiscoveryCredential, - V1DiscoveryCryptoMaterial, V1, - }, - BroadcastCryptoMaterial, EmptyMatchedCredential, KeySeedMatchedCredential, MatchableCredential, - MetadataDecryptionError, ProtocolVersion, ReferencedMatchedCredential, - SimpleBroadcastCryptoMaterial, + v1::{V1BroadcastCredential, V1DiscoveryCredential, V1DiscoveryCryptoMaterial, V1}, + MatchableCredential, }; -use crate::legacy::ShortMetadataKey; -use crate::MetadataKey; -use alloc::{vec, vec::Vec}; +use crate::extended::{V1IdentityToken, V1_IDENTITY_TOKEN_LEN}; +use alloc::vec::Vec; +use crypto_provider::{ed25519, CryptoProvider}; use crypto_provider_default::CryptoProviderImpl; +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; + fn get_zeroed_v0_discovery_credential() -> V0DiscoveryCredential { V0DiscoveryCredential::new([0u8; 32], [0u8; 32]) } fn get_constant_packed_v1_discovery_credential(value: u8) -> V1DiscoveryCredential { - let key_pair = np_ed25519::KeyPair::<CryptoProviderImpl>::generate(); - SimpleSignedBroadcastCryptoMaterial::new( + V1BroadcastCredential::new( [value; 32], - MetadataKey([value; 16]), + V1IdentityToken::from([value; V1_IDENTITY_TOKEN_LEN]), // NOTE: This winds up being unused in these test cases - key_pair.private_key(), + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), ) - .derive_v1_discovery_credential::<CryptoProviderImpl>() + .derive_discovery_credential::<CryptoProviderImpl>() } #[test] @@ -71,9 +71,11 @@ .iter() .map(|cred| { ( - cred.discovery_credential - .unsigned_verification_material::<CryptoProviderImpl>() - .mic_hmac_key, + *cred + .discovery_credential + .mic_extended_salt_verification_material::<CryptoProviderImpl>() + .mic_hmac_key() + .as_bytes(), ReferencedMatchedCredential::from(&cred.match_data), ) }) @@ -82,7 +84,10 @@ .iter() .map(|(crypto_material, match_data)| { ( - crypto_material.unsigned_verification_material::<CryptoProviderImpl>().mic_hmac_key, + *crypto_material + .mic_extended_salt_verification_material::<CryptoProviderImpl>() + .mic_hmac_key() + .as_bytes(), match_data, ) }) @@ -119,90 +124,13 @@ } } -#[test] -fn v0_metadata_decryption_works_same_metadata_key() { - let key_seed = [3u8; 32]; - let metadata_key = ShortMetadataKey([5u8; 14]); +mod coverage_gaming { + use crate::credential::MetadataDecryptionError; + use alloc::format; - let metadata = vec![7u8; 42]; - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); - - let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); - - let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); - - let decryption_result = V0::decrypt_metadata::<CryptoProviderImpl>( - metadata_nonce, - metadata_key, - &encrypted_metadata, - ); - assert_eq!(decryption_result, Ok(metadata)) -} - -#[test] -fn v1_metadata_decryption_works_same_metadata_key() { - let key_seed = [9u8; 32]; - let metadata_key = MetadataKey([2u8; 16]); - - let metadata = vec![6u8; 51]; - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); - - let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); - - let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); - - let decryption_result = V1::decrypt_metadata::<CryptoProviderImpl>( - metadata_nonce, - metadata_key, - &encrypted_metadata, - ); - assert_eq!(decryption_result, Ok(metadata)) -} - -#[test] -fn v0_metadata_decryption_fails_different_metadata_key() { - let key_seed = [3u8; 32]; - let encrypting_metadata_key = ShortMetadataKey([5u8; 14]); - - let metadata = vec![7u8; 42]; - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, encrypting_metadata_key); - - let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); - - let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); - - let decrypting_metadata_key = ShortMetadataKey([6u8; 14]); - - let decryption_result = V0::decrypt_metadata::<CryptoProviderImpl>( - metadata_nonce, - decrypting_metadata_key, - &encrypted_metadata, - ); - assert_eq!(decryption_result, Err(MetadataDecryptionError)) -} - -#[test] -fn v1_metadata_decryption_fails_different_metadata_key() { - let key_seed = [251u8; 32]; - let encrypting_metadata_key = MetadataKey([127u8; 16]); - - let metadata = vec![255u8; 42]; - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, encrypting_metadata_key); - - let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); - - let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); - - let decrypting_metadata_key = MetadataKey([249u8; 16]); - - let decryption_result = V1::decrypt_metadata::<CryptoProviderImpl>( - metadata_nonce, - decrypting_metadata_key, - &encrypted_metadata, - ); - assert_eq!(decryption_result, Err(MetadataDecryptionError)) + #[test] + fn metadata_decryption_error_debug() { + let err = MetadataDecryptionError; + let _ = format!("{:?}", err); + } }
diff --git a/nearby/presence/np_adv/src/credential/v0.rs b/nearby/presence/np_adv/src/credential/v0.rs index c89909d..84ff768 100644 --- a/nearby/presence/np_adv/src/credential/v0.rs +++ b/nearby/presence/np_adv/src/credential/v0.rs
@@ -13,39 +13,42 @@ // limitations under the License. //! Cryptographic materials for v0 advertisement-format credentials. -use crate::credential::{protocol_version_seal, DiscoveryCryptoMaterial, ProtocolVersion}; -use crate::legacy::ShortMetadataKey; -use crate::MetadataKey; -use crypto_provider::{CryptoProvider, CryptoRng}; +use crate::credential::{protocol_version_seal, DiscoveryMetadataCryptoMaterial, ProtocolVersion}; +use crypto_provider::{aead::Aead, aes, aes::ctr, CryptoProvider}; +use ldt_np_adv::V0IdentityToken; +use np_hkdf::NpKeySeedHkdf; /// Cryptographic information about a particular V0 discovery credential /// necessary to match and decrypt encrypted V0 advertisements. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct V0DiscoveryCredential { - key_seed: [u8; 32], - legacy_metadata_key_hmac: [u8; 32], + /// The 32-byte key-seed used for generating other key material. + pub key_seed: [u8; 32], + + /// The (LDT-variant) HMAC of the identity token. + pub expected_identity_token_hmac: [u8; 32], } impl V0DiscoveryCredential { /// Construct an [V0DiscoveryCredential] from the provided identity data. - pub fn new(key_seed: [u8; 32], legacy_metadata_key_hmac: [u8; 32]) -> Self { - Self { key_seed, legacy_metadata_key_hmac } + pub fn new(key_seed: [u8; 32], expected_identity_token_hmac: [u8; 32]) -> Self { + Self { key_seed, expected_identity_token_hmac } } } -impl DiscoveryCryptoMaterial<V0> for V0DiscoveryCredential { +impl DiscoveryMetadataCryptoMaterial<V0> for V0DiscoveryCredential { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { - V0::metadata_nonce_from_key_seed::<C>(&self.key_seed) + np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed).v0_metadata_nonce() } } impl V0DiscoveryCryptoMaterial for V0DiscoveryCredential { - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C> { - let hkdf = np_hkdf::NpKeySeedHkdf::new(&self.key_seed); + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> { + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); ldt_np_adv::build_np_adv_decrypter( - &hkdf.legacy_ldt_key(), - self.legacy_metadata_key_hmac, - hkdf.legacy_metadata_key_hmac_key(), + &hkdf.v0_ldt_key(), + self.expected_identity_token_hmac, + hkdf.v0_identity_token_hmac_key(), ) } } @@ -58,17 +61,17 @@ impl ProtocolVersion for V0 { type DiscoveryCredential = V0DiscoveryCredential; - type MetadataKey = ShortMetadataKey; + type IdentityToken = V0IdentityToken; - fn metadata_nonce_from_key_seed<C: CryptoProvider>(key_seed: &[u8; 32]) -> [u8; 12] { - let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(key_seed); - hkdf.legacy_metadata_nonce() + fn metadata_nonce_from_key_seed<C: CryptoProvider>( + hkdf: &NpKeySeedHkdf<C>, + ) -> <C::Aes128Gcm as Aead>::Nonce { + hkdf.v0_metadata_nonce() } - fn expand_metadata_key<C: CryptoProvider>(metadata_key: ShortMetadataKey) -> MetadataKey { - metadata_key.expand::<C>() - } - fn gen_random_metadata_key<R: CryptoRng>(rng: &mut R) -> ShortMetadataKey { - ShortMetadataKey(rng.gen()) + + // TODO should be IdP specific + fn extract_metadata_key<C: CryptoProvider>(metadata_key: V0IdentityToken) -> aes::Aes128Key { + np_hkdf::v0_metadata_expanded_key::<C>(&metadata_key.bytes()).into() } } @@ -83,18 +86,18 @@ /// be stored in implementors of this trait. // Space-time tradeoffs: // - LDT keys (64b) take about 1.4us. -pub trait V0DiscoveryCryptoMaterial: DiscoveryCryptoMaterial<V0> { +pub trait V0DiscoveryCryptoMaterial: DiscoveryMetadataCryptoMaterial<V0> { /// Returns an LDT NP advertisement cipher built with the provided `Aes` - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C>; + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C>; } /// [`V0DiscoveryCryptoMaterial`] that minimizes CPU time when providing key material at /// the expense of occupied memory. pub struct PrecalculatedV0DiscoveryCryptoMaterial { pub(crate) legacy_ldt_key: ldt::LdtKey<xts_aes::XtsAes128Key>, - pub(crate) legacy_metadata_key_hmac: [u8; 32], - pub(crate) legacy_metadata_key_hmac_key: [u8; 32], - pub(crate) metadata_nonce: [u8; 12], + pub(crate) legacy_identity_token_hmac: [u8; 32], + pub(crate) legacy_identity_token_hmac_key: [u8; 32], + pub(crate) metadata_nonce: ctr::AesCtrNonce, } impl PrecalculatedV0DiscoveryCryptoMaterial { @@ -102,26 +105,26 @@ pub(crate) fn new<C: CryptoProvider>(discovery_credential: &V0DiscoveryCredential) -> Self { let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&discovery_credential.key_seed); Self { - legacy_ldt_key: hkdf.legacy_ldt_key(), - legacy_metadata_key_hmac: discovery_credential.legacy_metadata_key_hmac, - legacy_metadata_key_hmac_key: *hkdf.legacy_metadata_key_hmac_key().as_bytes(), - metadata_nonce: hkdf.legacy_metadata_nonce(), + legacy_ldt_key: hkdf.v0_ldt_key(), + legacy_identity_token_hmac: discovery_credential.expected_identity_token_hmac, + legacy_identity_token_hmac_key: *hkdf.v0_identity_token_hmac_key().as_bytes(), + metadata_nonce: hkdf.v0_metadata_nonce(), } } } -impl DiscoveryCryptoMaterial<V0> for PrecalculatedV0DiscoveryCryptoMaterial { +impl DiscoveryMetadataCryptoMaterial<V0> for PrecalculatedV0DiscoveryCryptoMaterial { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { self.metadata_nonce } } impl V0DiscoveryCryptoMaterial for PrecalculatedV0DiscoveryCryptoMaterial { - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C> { + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> { ldt_np_adv::build_np_adv_decrypter( &self.legacy_ldt_key, - self.legacy_metadata_key_hmac, - self.legacy_metadata_key_hmac_key.into(), + self.legacy_identity_token_hmac, + self.legacy_identity_token_hmac_key.into(), ) } } @@ -129,26 +132,65 @@ // Implementations for reference types -- we don't provide a blanket impl for references // due to the potential to conflict with downstream crates' implementations. -impl<'a> DiscoveryCryptoMaterial<V0> for &'a V0DiscoveryCredential { +impl<'a> DiscoveryMetadataCryptoMaterial<V0> for &'a V0DiscoveryCredential { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { (*self).metadata_nonce::<C>() } } impl<'a> V0DiscoveryCryptoMaterial for &'a V0DiscoveryCredential { - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C> { + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> { (*self).ldt_adv_cipher::<C>() } } -impl<'a> DiscoveryCryptoMaterial<V0> for &'a PrecalculatedV0DiscoveryCryptoMaterial { +impl<'a> DiscoveryMetadataCryptoMaterial<V0> for &'a PrecalculatedV0DiscoveryCryptoMaterial { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { (*self).metadata_nonce::<C>() } } impl<'a> V0DiscoveryCryptoMaterial for &'a PrecalculatedV0DiscoveryCryptoMaterial { - fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C> { + fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> { (*self).ldt_adv_cipher::<C>() } } + +/// Crypto material for creating V1 advertisements. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct V0BroadcastCredential { + /// The 32-byte key-seed used for generating other key material. + pub key_seed: [u8; 32], + + /// The 14-byte identity-token which identifies the sender. + pub identity_token: V0IdentityToken, +} + +impl V0BroadcastCredential { + /// Builds some simple broadcast crypto-materials out of + /// the provided key-seed and version-specific metadata-key. + pub fn new(key_seed: [u8; 32], identity_token: V0IdentityToken) -> Self { + Self { key_seed, identity_token } + } + + /// Key seed from which other keys are derived. + pub(crate) fn key_seed(&self) -> [u8; 32] { + self.key_seed + } + + /// Identity token that will be incorporated into encrypted advertisements. + pub(crate) fn identity_token(&self) -> V0IdentityToken { + self.identity_token + } + + /// Derive a discovery credential with the data necessary to discover advertisements produced + /// by this broadcast credential. + pub fn derive_discovery_credential<C: CryptoProvider>(&self) -> V0DiscoveryCredential { + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); + + V0DiscoveryCredential::new( + self.key_seed, + hkdf.v0_identity_token_hmac_key().calculate_hmac::<C>(&self.identity_token.bytes()), + ) + } +}
diff --git a/nearby/presence/np_adv/src/credential/v1.rs b/nearby/presence/np_adv/src/credential/v1.rs index c13487d..b6b9c71 100644 --- a/nearby/presence/np_adv/src/credential/v1.rs +++ b/nearby/presence/np_adv/src/credential/v1.rs
@@ -14,92 +14,71 @@ //! Cryptographic materials for v1 advertisement-format credentials. -use crate::credential::{ - protocol_version_seal, BroadcastCryptoMaterial, DiscoveryCryptoMaterial, ProtocolVersion, -}; -use crate::MetadataKey; -use crypto_provider::ed25519::InvalidPublicKeyBytes; -use crypto_provider::{aes::Aes128Key, ed25519, ed25519::PublicKey, CryptoProvider, CryptoRng}; -use np_hkdf::UnsignedSectionKeys; +use crate::credential::{protocol_version_seal, DiscoveryMetadataCryptoMaterial, ProtocolVersion}; +use crate::extended::V1IdentityToken; +use crypto_provider::{aead::Aead, aes, ed25519, CryptoProvider}; +use np_hkdf::{DerivedSectionKeys, NpKeySeedHkdf}; /// Cryptographic information about a particular V1 discovery credential /// necessary to match and decrypt encrypted V1 sections. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct V1DiscoveryCredential { - key_seed: [u8; 32], - expected_unsigned_metadata_key_hmac: [u8; 32], - expected_signed_metadata_key_hmac: [u8; 32], - validated_pub_key: sealed::ValidatedPublicKey, + /// The 32-byte key-seed used for generating other key material. + pub key_seed: [u8; 32], + + /// The MIC-short-salt variant of the HMAC of the identity token. + pub expected_mic_short_salt_identity_token_hmac: [u8; 32], + + /// The MIC-extended-salt variant of the HMAC of the identity token. + pub expected_mic_extended_salt_identity_token_hmac: [u8; 32], + + /// The signed-extended-salt variant of the HMAC of the identity token. + pub expected_signed_extended_salt_identity_token_hmac: [u8; 32], + + /// The ed25519 public key used for verification of signed sections. + pub public_key: ed25519::PublicKey, } -mod sealed { - use crypto_provider::ed25519::InvalidPublicKeyBytes; - use crypto_provider::{ed25519, CryptoProvider}; - - // Wrapper of raw public ed25519 key bytes indicating the bytes stored - // actually represent a valid "edwards y" format and that said compressed - // point is actually a point on the curve. - #[derive(Clone, Copy)] - pub(crate) struct ValidatedPublicKey(ed25519::RawPublicKey); - - impl ValidatedPublicKey { - pub(crate) fn from_raw_bytes<C: CryptoProvider>( - bytes: ed25519::RawPublicKey, - ) -> Result<Self, InvalidPublicKeyBytes> { - np_ed25519::PublicKey::<C>::from_bytes(&bytes) - .map(|_| Self(bytes)) - .map_err(|_| InvalidPublicKeyBytes) - } - - pub(crate) fn to_public_key<C: CryptoProvider>(self) -> np_ed25519::PublicKey<C> { - np_ed25519::PublicKey::<C>::from_bytes(&self.0) - .expect("The public key bytes were validated on construction") - } - } -} -pub(crate) use sealed::ValidatedPublicKey; - impl V1DiscoveryCredential { /// Construct a V1 discovery credential from the provided identity data. - pub fn new<C: CryptoProvider>( + pub fn new( key_seed: [u8; 32], - expected_unsigned_metadata_key_hmac: [u8; 32], - expected_signed_metadata_key_hmac: [u8; 32], - pub_key: ed25519::RawPublicKey, - ) -> Result<Self, InvalidPublicKeyBytes> { - ValidatedPublicKey::from_raw_bytes::<C>(pub_key) - .map(|validated_pub_key| Self { - key_seed, - expected_unsigned_metadata_key_hmac, - expected_signed_metadata_key_hmac, - validated_pub_key, - }) - .map_err(|_| InvalidPublicKeyBytes) + expected_mic_short_salt_identity_token_hmac: [u8; 32], + expected_mic_extended_salt_identity_token_hmac: [u8; 32], + expected_signed_extended_salt_identity_token_hmac: [u8; 32], + public_key: ed25519::PublicKey, + ) -> Self { + Self { + key_seed, + expected_mic_short_salt_identity_token_hmac, + expected_mic_extended_salt_identity_token_hmac, + expected_signed_extended_salt_identity_token_hmac, + public_key, + } } /// Constructs pre-calculated crypto material from this discovery credential. pub(crate) fn to_precalculated<C: CryptoProvider>( &self, ) -> PrecalculatedV1DiscoveryCryptoMaterial { - let signed_identity_resolution_material = self.signed_identity_resolution_material::<C>(); - let unsigned_identity_resolution_material = - self.unsigned_identity_resolution_material::<C>(); - let signed_verification_material = self.signed_verification_material::<C>(); - let unsigned_verification_material = self.unsigned_verification_material::<C>(); - let metadata_nonce = self.metadata_nonce::<C>(); PrecalculatedV1DiscoveryCryptoMaterial { - signed_identity_resolution_material, - unsigned_identity_resolution_material, - signed_verification_material, - unsigned_verification_material, - metadata_nonce, + signed_identity_resolution_material: self.signed_identity_resolution_material::<C>(), + mic_short_salt_identity_resolution_material: self + .mic_short_salt_identity_resolution_material::<C>(), + mic_extended_salt_identity_resolution_material: self + .mic_extended_salt_identity_resolution_material::<C>(), + signed_verification_material: self.signed_verification_material::<C>(), + mic_short_salt_verification_material: self.mic_short_salt_verification_material::<C>(), + mic_extended_salt_verification_material: self + .mic_extended_salt_verification_material::<C>(), + metadata_nonce: self.metadata_nonce::<C>(), } } } -impl DiscoveryCryptoMaterial<V1> for V1DiscoveryCredential { +impl DiscoveryMetadataCryptoMaterial<V1> for V1DiscoveryCredential { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { - V1::metadata_nonce_from_key_seed::<C>(&self.key_seed) + np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed).v1_metadata_nonce() } } @@ -108,32 +87,50 @@ &self, ) -> SignedSectionIdentityResolutionMaterial { let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); - SignedSectionIdentityResolutionMaterial::from_hkdf_and_expected_metadata_key_hmac( + SignedSectionIdentityResolutionMaterial::from_hkdf_and_expected_identity_token_hmac( &hkdf, - self.expected_signed_metadata_key_hmac, + self.expected_signed_extended_salt_identity_token_hmac, ) } - fn unsigned_identity_resolution_material<C: CryptoProvider>( + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial { + ) -> MicShortSaltSectionIdentityResolutionMaterial { let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); - UnsignedSectionIdentityResolutionMaterial::from_hkdf_and_expected_metadata_key_hmac( + MicShortSaltSectionIdentityResolutionMaterial::from_hkdf_and_expected_identity_token_hmac( &hkdf, - self.expected_unsigned_metadata_key_hmac, + self.expected_mic_short_salt_identity_token_hmac, + ) + } + + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial { + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); + MicExtendedSaltSectionIdentityResolutionMaterial::from_hkdf_and_expected_identity_token_hmac( + &hkdf, + self.expected_mic_extended_salt_identity_token_hmac, ) } fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial { - SignedSectionVerificationMaterial { validated_public_key: self.validated_pub_key } + SignedSectionVerificationMaterial { public_key: self.public_key.clone() } } - fn unsigned_verification_material<C: CryptoProvider>( + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial { + ) -> MicShortSaltSectionVerificationMaterial { let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); - let mic_hmac_key = *UnsignedSectionKeys::hmac_key(&hkdf).as_bytes(); - UnsignedSectionVerificationMaterial { mic_hmac_key } + let mic_hmac_key = *hkdf.v1_mic_short_salt_keys().mic_hmac_key().as_bytes(); + MicShortSaltSectionVerificationMaterial { mic_hmac_key } + } + + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial { + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&self.key_seed); + let mic_hmac_key = *hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes(); + MicExtendedSaltSectionVerificationMaterial { mic_hmac_key } } } @@ -145,17 +142,18 @@ impl ProtocolVersion for V1 { type DiscoveryCredential = V1DiscoveryCredential; - type MetadataKey = MetadataKey; + type IdentityToken = V1IdentityToken; - fn metadata_nonce_from_key_seed<C: CryptoProvider>(key_seed: &[u8; 32]) -> [u8; 12] { - let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(key_seed); - hkdf.extended_metadata_nonce() + fn metadata_nonce_from_key_seed<C: CryptoProvider>( + hkdf: &NpKeySeedHkdf<C>, + ) -> <C::Aes128Gcm as Aead>::Nonce { + hkdf.v1_metadata_nonce() } - fn expand_metadata_key<C: CryptoProvider>(metadata_key: MetadataKey) -> MetadataKey { - metadata_key - } - fn gen_random_metadata_key<R: CryptoRng>(rng: &mut R) -> MetadataKey { - MetadataKey(rng.gen()) + + fn extract_metadata_key<C: CryptoProvider>( + identity_token: Self::IdentityToken, + ) -> aes::Aes128Key { + identity_token.into_bytes().into() } } @@ -173,12 +171,12 @@ #[derive(Clone)] pub(crate) struct SectionIdentityResolutionMaterial { /// The AES key for decrypting section ciphertext - pub(crate) aes_key: Aes128Key, - /// The metadata key HMAC key for deriving and verifying the identity metadata + pub(crate) aes_key: aes::Aes128Key, + /// The identity token HMAC key for deriving and verifying the identity metadata /// key HMAC against the expected value. - pub(crate) metadata_key_hmac_key: [u8; 32], - /// The expected metadata key HMAC to check against for an identity match. - pub(crate) expected_metadata_key_hmac: [u8; 32], + pub(crate) identity_token_hmac_key: [u8; 32], + /// The expected identity token HMAC to check against for an identity match. + pub(crate) expected_identity_token_hmac: [u8; 32], } /// Cryptographic materials necessary for determining whether or not @@ -206,50 +204,97 @@ /// Constructs identity-resolution material for a signed section whose /// discovery credential leverages the provided HKDF and has the given /// expected metadata-key HMAC. - pub(crate) fn from_hkdf_and_expected_metadata_key_hmac<C: CryptoProvider>( + pub(crate) fn from_hkdf_and_expected_identity_token_hmac<C: CryptoProvider>( hkdf: &np_hkdf::NpKeySeedHkdf<C>, - expected_metadata_key_hmac: [u8; 32], + expected_identity_token_hmac: [u8; 32], ) -> Self { Self(SectionIdentityResolutionMaterial { - aes_key: hkdf.extended_signed_section_aes_key(), - metadata_key_hmac_key: *hkdf.extended_signed_metadata_key_hmac_key().as_bytes(), - expected_metadata_key_hmac, + aes_key: hkdf.v1_signature_keys().aes_key(), + identity_token_hmac_key: *hkdf.v1_signature_keys().identity_token_hmac_key().as_bytes(), + expected_identity_token_hmac, }) } } /// Cryptographic materials necessary for determining whether or not -/// a given V1 MIC advertisement section matches an identity. +/// a given V1 MIC extended salt advertisement section matches an identity. #[derive(Clone)] -pub struct UnsignedSectionIdentityResolutionMaterial(SectionIdentityResolutionMaterial); +pub struct MicExtendedSaltSectionIdentityResolutionMaterial(SectionIdentityResolutionMaterial); -impl UnsignedSectionIdentityResolutionMaterial { - #[cfg(test)] - pub(crate) fn from_raw(raw: SectionIdentityResolutionMaterial) -> Self { - Self(raw) - } +impl MicExtendedSaltSectionIdentityResolutionMaterial { /// Extracts the underlying section-identity resolution material carried around - /// within this wrapper for resolution of unsigned sections. + /// within this wrapper for resolution of MIC extended salt sections. pub(crate) fn into_raw_resolution_material(self) -> SectionIdentityResolutionMaterial { self.0 } /// Gets the underlying section-identity resolution material carried around - /// within this wrapper for resolution of unsigned sections. + /// within this wrapper for resolution of MIC extended salt sections. #[cfg(any(test, feature = "devtools"))] pub(crate) fn as_raw_resolution_material(&self) -> &SectionIdentityResolutionMaterial { &self.0 } - /// Constructs identity-resolution material for an unsigned (MIC) section whose + #[cfg(test)] + pub(crate) fn as_mut_raw_resolution_material( + &mut self, + ) -> &mut SectionIdentityResolutionMaterial { + &mut self.0 + } + /// Constructs identity-resolution material for an MIC extended salt section whose /// discovery credential leverages the provided HKDF and has the given /// expected metadata-key HMAC. - pub(crate) fn from_hkdf_and_expected_metadata_key_hmac<C: CryptoProvider>( + pub(crate) fn from_hkdf_and_expected_identity_token_hmac<C: CryptoProvider>( hkdf: &np_hkdf::NpKeySeedHkdf<C>, - expected_metadata_key_hmac: [u8; 32], + expected_identity_token_hmac: [u8; 32], ) -> Self { Self(SectionIdentityResolutionMaterial { - aes_key: UnsignedSectionKeys::aes_key(hkdf), - metadata_key_hmac_key: *hkdf.extended_unsigned_metadata_key_hmac_key().as_bytes(), - expected_metadata_key_hmac, + aes_key: hkdf.v1_mic_extended_salt_keys().aes_key(), + identity_token_hmac_key: *hkdf + .v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .as_bytes(), + expected_identity_token_hmac, + }) + } +} + +/// Cryptographic materials necessary for determining whether +/// a given V1 MIC short salt advertisement section matches an identity. +#[derive(Clone)] +pub struct MicShortSaltSectionIdentityResolutionMaterial(SectionIdentityResolutionMaterial); + +impl MicShortSaltSectionIdentityResolutionMaterial { + /// Extracts the underlying section-identity resolution material carried around + /// within this wrapper for resolution of MIC short salt sections. + pub(crate) fn into_raw_resolution_material(self) -> SectionIdentityResolutionMaterial { + self.0 + } + /// Gets the underlying section-identity resolution material carried around + /// within this wrapper for resolution of MIC short salt sections. + #[cfg(any(test, feature = "devtools"))] + pub(crate) fn as_raw_resolution_material(&self) -> &SectionIdentityResolutionMaterial { + &self.0 + } + #[cfg(test)] + pub(crate) fn as_mut_raw_resolution_material( + &mut self, + ) -> &mut SectionIdentityResolutionMaterial { + &mut self.0 + } + + /// Constructs identity-resolution material for a MIC short salt section whose + /// discovery credential leverages the provided HKDF and has the given + /// expected metadata-key HMAC. + pub(crate) fn from_hkdf_and_expected_identity_token_hmac<C: CryptoProvider>( + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + expected_identity_token_hmac: [u8; 32], + ) -> Self { + Self(SectionIdentityResolutionMaterial { + aes_key: hkdf.v1_mic_short_salt_keys().aes_key(), + identity_token_hmac_key: *hkdf + .v1_mic_short_salt_keys() + .identity_token_hmac_key() + .as_bytes(), + expected_identity_token_hmac, }) } } @@ -260,34 +305,50 @@ pub struct SignedSectionVerificationMaterial { /// The np_ed25519 public key to be /// used for signature verification of signed sections. - pub(crate) validated_public_key: sealed::ValidatedPublicKey, + pub(crate) public_key: ed25519::PublicKey, } impl SignedSectionVerificationMaterial { /// Gets the np_ed25519 public key for the given identity, /// used for signature verification of signed sections. - pub(crate) fn signature_verification_public_key<C: CryptoProvider>( - &self, - ) -> np_ed25519::PublicKey<C> { - self.validated_public_key.to_public_key() + pub(crate) fn signature_verification_public_key(&self) -> ed25519::PublicKey { + self.public_key.clone() } } -/// Crypto materials for V1 unsigned sections which are not employed in identity resolution, -/// but may be necessary to fully decrypt an unsigned section. +/// Crypto materials for V1 MIC short salt sections which are not employed in identity resolution, +/// but may be necessary to fully decrypt a MIC short salt section. #[derive(Clone)] -pub struct UnsignedSectionVerificationMaterial { - /// The MIC HMAC key for verifying the integrity of unsigned sections. +pub struct MicShortSaltSectionVerificationMaterial { + /// The MIC HMAC key for verifying the integrity of MIC short salt sections. pub(crate) mic_hmac_key: [u8; 32], } -impl UnsignedSectionVerificationMaterial { - /// Returns the MIC HMAC key for unsigned sections - pub(crate) fn mic_hmac_key<C: CryptoProvider>(&self) -> np_hkdf::NpHmacSha256Key<C> { +impl MicSectionVerificationMaterial for MicShortSaltSectionVerificationMaterial { + fn mic_hmac_key(&self) -> np_hkdf::NpHmacSha256Key { self.mic_hmac_key.into() } } +/// Crypto materials for V1 MIC extended salt sections which are not employed in identity +/// resolution, but may be necessary to fully decrypt a MIC extended salt section. +#[derive(Clone)] +pub struct MicExtendedSaltSectionVerificationMaterial { + /// The MIC HMAC key for verifying the integrity of MIC extended salt sections. + pub(crate) mic_hmac_key: [u8; 32], +} + +impl MicSectionVerificationMaterial for MicExtendedSaltSectionVerificationMaterial { + fn mic_hmac_key(&self) -> np_hkdf::NpHmacSha256Key { + self.mic_hmac_key.into() + } +} + +pub(crate) trait MicSectionVerificationMaterial { + /// Returns the HMAC key for calculating the MIC of the sections + fn mic_hmac_key(&self) -> np_hkdf::NpHmacSha256Key; +} + // Space-time tradeoffs: // - Calculating an HKDF from the key seed costs about 2us on a gLinux laptop, and occupies 80b. // - Calculating an AES (16b) or HMAC (32b) key from the HKDF costs about 700ns. @@ -299,39 +360,54 @@ // is only used on the matching identity, not all identities. /// Cryptographic material for an individual NP credential used to decrypt and verify v1 sections. -pub trait V1DiscoveryCryptoMaterial: DiscoveryCryptoMaterial<V1> { +pub trait V1DiscoveryCryptoMaterial: DiscoveryMetadataCryptoMaterial<V1> { /// Constructs or copies the identity resolution material for signed sections fn signed_identity_resolution_material<C: CryptoProvider>( &self, ) -> SignedSectionIdentityResolutionMaterial; - /// Constructs or copies the identity resolution material for unsigned sections - fn unsigned_identity_resolution_material<C: CryptoProvider>( + /// Constructs or copies the identity resolution material for MIC short salt sections + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial; + ) -> MicShortSaltSectionIdentityResolutionMaterial; + + /// Constructs or copies the identity resolution material for MIC extended salt sections + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial; /// Constructs or copies non-identity-resolution deserialization material for signed /// sections. fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial; - /// Constructs or copies non-identity-resolution deserialization material for unsigned + /// Constructs or copies non-identity-resolution deserialization material for MIC short salt /// sections. - fn unsigned_verification_material<C: CryptoProvider>( + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial; + ) -> MicShortSaltSectionVerificationMaterial; + + /// Constructs or copies non-identity-resolution deserialization material for MIC extended salt + /// sections. + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial; } -/// V1 [`DiscoveryCryptoMaterial`] that minimizes CPU time when providing key material at +/// [`V1DiscoveryCryptoMaterial`] that minimizes CPU time when providing key material at /// the expense of occupied memory pub struct PrecalculatedV1DiscoveryCryptoMaterial { pub(crate) signed_identity_resolution_material: SignedSectionIdentityResolutionMaterial, - pub(crate) unsigned_identity_resolution_material: UnsignedSectionIdentityResolutionMaterial, + pub(crate) mic_short_salt_identity_resolution_material: + MicShortSaltSectionIdentityResolutionMaterial, + pub(crate) mic_extended_salt_identity_resolution_material: + MicExtendedSaltSectionIdentityResolutionMaterial, pub(crate) signed_verification_material: SignedSectionVerificationMaterial, - pub(crate) unsigned_verification_material: UnsignedSectionVerificationMaterial, + pub(crate) mic_short_salt_verification_material: MicShortSaltSectionVerificationMaterial, + pub(crate) mic_extended_salt_verification_material: MicExtendedSaltSectionVerificationMaterial, pub(crate) metadata_nonce: [u8; 12], } -impl DiscoveryCryptoMaterial<V1> for PrecalculatedV1DiscoveryCryptoMaterial { +impl DiscoveryMetadataCryptoMaterial<V1> for PrecalculatedV1DiscoveryCryptoMaterial { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { self.metadata_nonce } @@ -343,25 +419,39 @@ ) -> SignedSectionIdentityResolutionMaterial { self.signed_identity_resolution_material.clone() } - fn unsigned_identity_resolution_material<C: CryptoProvider>( + + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial { - self.unsigned_identity_resolution_material.clone() + ) -> MicShortSaltSectionIdentityResolutionMaterial { + self.mic_short_salt_identity_resolution_material.clone() + } + + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial { + self.mic_extended_salt_identity_resolution_material.clone() } fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial { self.signed_verification_material.clone() } - fn unsigned_verification_material<C: CryptoProvider>( + + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial { - self.unsigned_verification_material.clone() + ) -> MicShortSaltSectionVerificationMaterial { + self.mic_short_salt_verification_material.clone() + } + + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial { + self.mic_extended_salt_verification_material.clone() } } // Implementations for reference types -- we don't provide a blanket impl for references // due to the potential to conflict with downstream crates' implementations. -impl<'a> DiscoveryCryptoMaterial<V1> for &'a V1DiscoveryCredential { +impl<'a> DiscoveryMetadataCryptoMaterial<V1> for &'a V1DiscoveryCredential { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { (*self).metadata_nonce::<C>() } @@ -373,22 +463,36 @@ ) -> SignedSectionIdentityResolutionMaterial { (*self).signed_identity_resolution_material::<C>() } - fn unsigned_identity_resolution_material<C: CryptoProvider>( + + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial { - (*self).unsigned_identity_resolution_material::<C>() + ) -> MicShortSaltSectionIdentityResolutionMaterial { + (*self).mic_short_salt_identity_resolution_material::<C>() + } + + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial { + (*self).mic_extended_salt_identity_resolution_material::<C>() } fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial { (*self).signed_verification_material::<C>() } - fn unsigned_verification_material<C: CryptoProvider>( + + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial { - (*self).unsigned_verification_material::<C>() + ) -> MicShortSaltSectionVerificationMaterial { + (*self).mic_short_salt_verification_material::<C>() + } + + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial { + (*self).mic_extended_salt_verification_material::<C>() } } -impl<'a> DiscoveryCryptoMaterial<V1> for &'a PrecalculatedV1DiscoveryCryptoMaterial { +impl<'a> DiscoveryMetadataCryptoMaterial<V1> for &'a PrecalculatedV1DiscoveryCryptoMaterial { fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] { (*self).metadata_nonce::<C>() } @@ -400,84 +504,92 @@ ) -> SignedSectionIdentityResolutionMaterial { (*self).signed_identity_resolution_material::<C>() } - fn unsigned_identity_resolution_material<C: CryptoProvider>( + + fn mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionIdentityResolutionMaterial { - (*self).unsigned_identity_resolution_material::<C>() + ) -> MicShortSaltSectionIdentityResolutionMaterial { + (*self).mic_short_salt_identity_resolution_material::<C>() + } + + fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionIdentityResolutionMaterial { + (*self).mic_extended_salt_identity_resolution_material::<C>() } fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial { (*self).signed_verification_material::<C>() } - fn unsigned_verification_material<C: CryptoProvider>( + + fn mic_short_salt_verification_material<C: CryptoProvider>( &self, - ) -> UnsignedSectionVerificationMaterial { - (*self).unsigned_verification_material::<C>() + ) -> MicShortSaltSectionVerificationMaterial { + (*self).mic_short_salt_verification_material::<C>() + } + + fn mic_extended_salt_verification_material<C: CryptoProvider>( + &self, + ) -> MicExtendedSaltSectionVerificationMaterial { + (*self).mic_extended_salt_verification_material::<C>() } } -/// Extension of [`BroadcastCryptoMaterial`] for `V1` to add -/// crypto-materials which are necessary to sign V1 sections. -pub trait SignedBroadcastCryptoMaterial: BroadcastCryptoMaterial<V1> { - /// Gets the advertisement-signing private key for constructing - /// signature-verified V1 sections. - /// - /// The private key is returned in an opaque, crypto-provider-independent - /// form to provide a safeguard against leaking the bytes of the key. - fn signing_key(&self) -> ed25519::PrivateKey; +/// Crypto material for creating V1 sections. +#[derive(Clone)] +pub struct V1BroadcastCredential { + /// The 32-byte key-seed used for generating other key material. + pub key_seed: [u8; 32], - /// Constructs the V1 discovery credential which may be used to discover - /// V1 advertisement sections broadcasted using this broadcast crypto-material - fn derive_v1_discovery_credential<C: CryptoProvider>(&self) -> V1DiscoveryCredential { - let key_seed = self.key_seed(); - let metadata_key = self.metadata_key(); - let pub_key = self.signing_key().derive_public_key::<C::Ed25519>(); - let pub_key = pub_key.to_bytes(); + /// The 16-byte identity-token which identifies the sender. + pub identity_token: V1IdentityToken, - let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); - let unsigned = hkdf - .extended_unsigned_metadata_key_hmac_key() - .calculate_hmac(metadata_key.0.as_slice()); - let signed = - hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(metadata_key.0.as_slice()); - V1DiscoveryCredential::new::<C>(key_seed, unsigned, signed, pub_key).expect("The public key bytes are guaranteed to be valid since they come from the key_pair construction above") - } + /// The ed25519 private key to be used for signing section contents. + pub private_key: ed25519::PrivateKey, } -/// Concrete implementation of a [`SignedBroadcastCryptoMaterial`] which keeps the key -/// seed, the V1 metadata key, and the signing key contiguous in memory. -/// -/// For more flexible expression of broadcast -/// credentials, feel free to directly implement [`SignedBroadcastCryptoMaterial`] -/// for your own broadcast-credential-storing data-type. -pub struct SimpleSignedBroadcastCryptoMaterial { - key_seed: [u8; 32], - metadata_key: MetadataKey, - signing_key: ed25519::PrivateKey, -} - -impl SimpleSignedBroadcastCryptoMaterial { +impl V1BroadcastCredential { /// Builds some simple V1 signed broadcast crypto-materials out of - /// the provided key-seed, metadata-key, and signing key. + /// the provided key-seed, metadata-key, and ed25519 private key. pub fn new( key_seed: [u8; 32], - metadata_key: MetadataKey, - signing_key: ed25519::PrivateKey, + identity_token: V1IdentityToken, + private_key: ed25519::PrivateKey, ) -> Self { - Self { key_seed, metadata_key, signing_key } + Self { key_seed, identity_token, private_key } } -} -impl BroadcastCryptoMaterial<V1> for SimpleSignedBroadcastCryptoMaterial { - fn key_seed(&self) -> [u8; 32] { + /// Key seed from which other keys are derived. + pub(crate) fn key_seed(&self) -> [u8; 32] { self.key_seed } - fn metadata_key(&self) -> MetadataKey { - self.metadata_key - } -} -impl SignedBroadcastCryptoMaterial for SimpleSignedBroadcastCryptoMaterial { - fn signing_key(&self) -> ed25519::PrivateKey { - self.signing_key.clone() + /// Identity token that will be incorporated into encrypted advertisements. + pub(crate) fn identity_token(&self) -> V1IdentityToken { + self.identity_token + } + + /// Derive a discovery credential with the data necessary to discover advertisements produced + /// by this broadcast credential. + pub fn derive_discovery_credential<C: CryptoProvider>(&self) -> V1DiscoveryCredential { + let key_seed = self.key_seed(); + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); + + V1DiscoveryCredential::new( + key_seed, + hkdf.v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + hkdf.v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + hkdf.v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(self.identity_token.as_slice()), + self.signing_key().derive_public_key::<C::Ed25519>(), + ) + } + + /// Key used for signature-protected sections + pub(crate) fn signing_key(&self) -> ed25519::PrivateKey { + self.private_key.clone() } }
diff --git a/nearby/presence/np_adv/src/de_type.rs b/nearby/presence/np_adv/src/de_type.rs deleted file mode 100644 index 4966ed0..0000000 --- a/nearby/presence/np_adv/src/de_type.rs +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! DE types that are shared across v0 and v1. - -// The same ids are used for v0/legacy and v1/extended -const IDENTITY_DE_TYPES_BY_CODE: [Option<IdentityDataElementType>; 5] = [ - // no need for more elements since identity types are at indices 1-4 - None, // 0b0000 - Some(IdentityDataElementType::Private), // 0b0001 - Some(IdentityDataElementType::Trusted), // 0b0010 - Some(IdentityDataElementType::Public), // 0b0011 - Some(IdentityDataElementType::Provisioned), // 0b0100 -]; - -/// DE types for special DEs that contain other DEs and consume the entire payload of the -/// advertisement. -/// -/// Shared between V0 and V1. -/// -/// Must not overlap with [`PlainDataElementType`](crate::legacy::de_type::PlainDataElementType). -#[derive(strum_macros::EnumIter, Debug, Clone, Copy, PartialEq, Eq)] -#[allow(clippy::enum_variant_names)] -pub(crate) enum IdentityDataElementType { - Private, - Trusted, - Public, - Provisioned, -} - -impl IdentityDataElementType { - pub(crate) fn as_encrypted_identity_de_type(&self) -> Option<EncryptedIdentityDataElementType> { - match self { - IdentityDataElementType::Private => Some(EncryptedIdentityDataElementType::Private), - IdentityDataElementType::Trusted => Some(EncryptedIdentityDataElementType::Trusted), - IdentityDataElementType::Public => None, - IdentityDataElementType::Provisioned => { - Some(EncryptedIdentityDataElementType::Provisioned) - } - } - } - - /// Type codes for identity DEs are shared between versions 0 and 1. - pub(crate) fn shared_type_code(&self) -> u8 { - match self { - IdentityDataElementType::Private => 0b0001, - IdentityDataElementType::Trusted => 0b0010, - IdentityDataElementType::Public => 0b0011, - IdentityDataElementType::Provisioned => 0b0100, - } - } - - pub(crate) fn from_shared_type_code(code: u8) -> Option<Self> { - IDENTITY_DE_TYPES_BY_CODE.get(code as usize).and_then(|o| *o) - } -} - -/// The identity DE types that support encryption. -#[derive(strum_macros::EnumIter, Debug, Clone, Copy, PartialEq, Eq)] -pub enum EncryptedIdentityDataElementType { - /// An identity that's shared with other devices where a user has signed in to their identity provider - Private, - /// An identity shared via some trust designation (e.g. starred contacts) - Trusted, - /// An identity established via a p2p link between two specific devices - Provisioned, -} - -impl EncryptedIdentityDataElementType { - pub(crate) fn as_identity_data_element_type(&self) -> IdentityDataElementType { - match self { - EncryptedIdentityDataElementType::Private => IdentityDataElementType::Private, - EncryptedIdentityDataElementType::Trusted => IdentityDataElementType::Trusted, - EncryptedIdentityDataElementType::Provisioned => IdentityDataElementType::Provisioned, - } - } -}
diff --git a/nearby/presence/np_adv/src/deser_v1_tests.rs b/nearby/presence/np_adv/src/deser_v1_tests.rs deleted file mode 100644 index cdd9030..0000000 --- a/nearby/presence/np_adv/src/deser_v1_tests.rs +++ /dev/null
@@ -1,562 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -use core::marker::PhantomData; -use rand::{rngs::StdRng, seq::SliceRandom as _, Rng as _, SeedableRng as _}; - -extern crate std; - -use crate::{ - credential::{ - book::{CredentialBook, CredentialBookBuilder}, - v1::{ - SignedBroadcastCryptoMaterial, SimpleSignedBroadcastCryptoMaterial, - V1DiscoveryCredential, - }, - EmptyMatchedCredential, MatchableCredential, MatchedCredential, - }, - de_type::EncryptedIdentityDataElementType, - deserialization_arena, - deserialization_arena::DeserializationArena, - deserialize_advertisement, - extended::{ - data_elements::GenericDataElement, - deserialize::VerificationMode, - serialize::{ - AdvBuilder, AdvertisementType, EncodedAdvertisement, MicEncryptedSectionEncoder, - PublicSectionEncoder, SectionBuilder, SectionEncoder, SignedEncryptedSectionEncoder, - }, - }, - AdvDeserializationError, AdvDeserializationErrorDetailsHazmat, HasIdentityMatch, MetadataKey, - PlaintextIdentityMode, Section, V1AdvertisementContents, V1DeserializedSection, -}; -use crypto_provider::{CryptoProvider, CryptoRng}; -use std::{collections, prelude::rust_2021::*, vec}; -use strum::IntoEnumIterator as _; - -use crate::extended::NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT; -use crypto_provider_default::CryptoProviderImpl; - -#[test] -fn v1_plaintext() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let identities = (0..100) - .map(|_| TestIdentity::<CryptoProviderImpl>::random(&mut rng)) - .collect::<Vec<_>>(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let section_configs: Vec<SectionConfig<CryptoProviderImpl>> = - fill_plaintext_adv(&mut rng, &mut adv_builder); - let adv = adv_builder.into_advertisement(); - let creds = identities - .iter() - .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), - match_data: EmptyMatchedCredential, - }) - .collect::<Vec<_>>(); - - let arena = deserialization_arena!(); - // check if the section is empty or there is more than one public section - let cred_book = - CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &creds); - if section_configs.is_empty() { - let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!( - v1_error, - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError - } - ); //assert a adv deserialization error - } else { - let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!(0, v1_contents.invalid_sections_count()); - assert_eq!(section_configs.len(), v1_contents.sections.len()); - for (section_config, section) in section_configs.iter().zip(v1_contents.sections.iter()) - { - assert_section_equals(section_config, section); - } - } - } -} - -#[test] -fn v1_all_identities_resolvable_ciphertext() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let identities = (0..100) - .map(|_| TestIdentity::<CryptoProviderImpl>::random(&mut rng)) - .collect::<Vec<_>>(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let section_configs = fill_encrypted_adv(&mut rng, &identities, &mut adv_builder); - let adv = adv_builder.into_advertisement(); - let creds = identities - .iter() - .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), - match_data: EmptyMatchedCredential, - }) - .collect::<Vec<_>>(); - let arena = deserialization_arena!(); - // check if the section header would be 0 or if the section is empty - let cred_book = - CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &creds); - if section_configs.is_empty() { - let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!( - v1_error, - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError - } - ); //assert a adv deserialization error - } else { - let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!(0, v1_contents.invalid_sections_count()); - assert_eq!(section_configs.len(), v1_contents.sections.len()); - for (section_config, section) in section_configs.iter().zip(v1_contents.sections.iter()) - { - assert_section_equals(section_config, section); - } - } - } -} - -#[test] -fn v1_only_non_matching_identities_available_ciphertext() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let identities = (0..100) - .map(|_| TestIdentity::<CryptoProviderImpl>::random(&mut rng)) - .collect::<Vec<_>>(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let section_configs = fill_encrypted_adv(&mut rng, &identities, &mut adv_builder); - let adv = adv_builder.into_advertisement(); - let creds = identities - .iter() - .filter(|i| { - // remove all identities used in sections - !section_configs - .iter() - .any(|sc| sc.identity.map(|sci| sci.key_seed == i.key_seed).unwrap_or(false)) - }) - .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), - match_data: EmptyMatchedCredential, - }) - .collect::<Vec<_>>(); - - let arena = deserialization_arena!(); - // check if the section header would be 0 - let cred_book = - CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &creds); - if section_configs.is_empty() { - let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!( - v1_error, - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError - } - ); //assert a adv deserialization error - } else { - let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - // all encrypted identity sections are invalid - let encrypted_section_count = - section_configs.iter().filter(|sc| sc.identity.is_some()).count(); - assert_eq!(encrypted_section_count, v1_contents.invalid_sections_count()); - assert_eq!(section_configs.len() - encrypted_section_count, v1_contents.sections.len()); - for (section_config, section) in section_configs - .iter() - // skip encrypted sections - .filter(|sc| sc.identity.is_none()) - .zip(v1_contents.sections.iter()) - { - assert_section_equals(section_config, section); - } - } - } -} - -#[test] -fn v1_no_creds_available_ciphertext() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let identities = (0..100).map(|_| TestIdentity::random(&mut rng)).collect::<Vec<_>>(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let section_configs = fill_encrypted_adv::<StdRng, CryptoProviderImpl>( - &mut rng, - &identities, - &mut adv_builder, - ); - let adv = adv_builder.into_advertisement(); - let arena = deserialization_arena!(); - // check if the section header would be 0 - let cred_book = CredentialBookBuilder::<EmptyMatchedCredential>::build_cached_slice_book::< - 0, - 0, - CryptoProviderImpl, - >(&[], &[]); - if section_configs.is_empty() { - let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!( - v1_error, - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError - } - ); //assert a adv deserialization error - } else { - let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - // all encrypted identity sections are invalid - let encrypted_section_count = - section_configs.iter().filter(|sc| sc.identity.is_some()).count(); - assert_eq!(encrypted_section_count, v1_contents.invalid_sections_count()); - assert_eq!(section_configs.len() - encrypted_section_count, v1_contents.sections.len()); - - for (section_config, section) in section_configs - .iter() - // skip encrypted sections - .filter(|sc| sc.identity.is_none()) - .zip(v1_contents.sections.iter()) - { - assert_section_equals(section_config, section); - } - } - } -} - -#[test] -fn v1_only_some_matching_identities_available_ciphertext() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let identities = (0..100) - .map(|_| TestIdentity::<CryptoProviderImpl>::random(&mut rng)) - .collect::<Vec<_>>(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let section_configs = fill_encrypted_adv(&mut rng, &identities, &mut adv_builder); - let adv = adv_builder.into_advertisement(); - // identities used in sections, which may be used in multiple sections too - let identities_to_remove: collections::HashSet<_> = identities - .iter() - .filter(|i| { - let identity_used = section_configs - .iter() - .any(|sc| sc.identity.map(|sci| sci.key_seed == i.key_seed).unwrap_or(false)); - - // only remove half the identities that were used - identity_used && rng.gen() - }) - .map(|i| i.key_seed) - .collect(); - - let creds = identities - .iter() - .filter(|i| !identities_to_remove.contains(&i.key_seed)) - .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), - match_data: EmptyMatchedCredential, - }) - .collect::<Vec<_>>(); - - let arena = deserialization_arena!(); - - let cred_book = - CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &creds); - - // check if the section header would be 0 - if section_configs.is_empty() { - let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - assert_eq!( - v1_error, - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError - } - ); //assert a adv deserialization error - } else { - let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, &adv, &cred_book); - - let affected_sections: Vec<_> = section_configs - .iter() - .filter(|sc| { - sc.identity - .map(|sci| identities_to_remove.iter().any(|ks| &sci.key_seed == ks)) - .unwrap_or(false) - }) - .collect(); - - assert_eq!(affected_sections.len(), v1_contents.invalid_sections_count()); - assert_eq!(section_configs.len() - affected_sections.len(), v1_contents.sections.len()); - - for (section_config, section) in section_configs - .iter() - // skip sections w/ removed identities - .filter(|sc| { - sc.identity.map(|i| !identities_to_remove.contains(&i.key_seed)).unwrap_or(true) - }) - .zip(v1_contents.sections.iter()) - { - assert_section_equals(section_config, section); - } - } - } -} - -fn assert_section_equals<M: MatchedCredential, C: CryptoProvider>( - section_config: &SectionConfig<C>, - section: &V1DeserializedSection<M>, -) { - match section_config.identity { - None => match section { - V1DeserializedSection::Plaintext(p) => { - assert!(section_config.verification_mode.is_none()); - - assert_eq!(section_config.plaintext_mode.unwrap(), p.identity()); - assert_eq!( - section_config.data_elements, - p.iter_data_elements().map(|de| (&de.unwrap()).into()).collect::<Vec<_>>() - ) - } - V1DeserializedSection::Decrypted(_) => panic!("no id, but decrypted section"), - }, - Some(_) => match section { - V1DeserializedSection::Plaintext(_) => panic!("id, but plaintext section"), - V1DeserializedSection::Decrypted(wmc) => { - assert!(section_config.plaintext_mode.is_none()); - - assert_eq!( - section_config.data_elements, - wmc.contents() - .iter_data_elements() - .map(|de| (&de.unwrap()).into()) - .collect::<Vec<GenericDataElement>>() - ); - assert_eq!( - section_config.identity.unwrap().identity_type, - wmc.contents().identity_type() - ); - assert_eq!( - section_config.identity.unwrap().extended_metadata_key, - wmc.contents().metadata_key() - ); - assert_eq!( - section_config.verification_mode.unwrap(), - wmc.contents().verification_mode() - ); - } - }, - } -} - -fn deser_v1_error<'a, B, P>( - arena: DeserializationArena<'a>, - adv: &'a EncodedAdvertisement, - cred_book: &'a B, -) -> AdvDeserializationError -where - B: CredentialBook<'a>, - P: CryptoProvider, -{ - let v1_contents = match deserialize_advertisement::<_, P>(arena, adv.as_slice(), cred_book) { - Err(e) => e, - _ => panic!("Expecting an error!"), - }; - v1_contents -} - -fn deser_v1<'adv, B, P>( - arena: DeserializationArena<'adv>, - adv: &'adv EncodedAdvertisement, - cred_book: &'adv B, -) -> V1AdvertisementContents<'adv, B::Matched> -where - B: CredentialBook<'adv>, - P: CryptoProvider, -{ - deserialize_advertisement::<_, P>(arena, adv.as_slice(), cred_book) - .expect("Should be a valid advertisement") - .into_v1() - .expect("Should be V1") -} - -/// Populate a random number of sections with randomly chosen identities and random DEs -fn fill_plaintext_adv<'a, R: rand::Rng, C: CryptoProvider>( - mut rng: &mut R, - adv_builder: &mut AdvBuilder, -) -> Vec<SectionConfig<'a, C>> { - let mut expected = Vec::new(); - // build sections - for _ in 0..rng.gen_range(0..=NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT) { - let res = adv_builder.section_builder(PublicSectionEncoder::default()).map(|s| { - SectionConfig::new( - None, - Some(PlaintextIdentityMode::Public), - None, - add_des(s, &mut rng), - ) - }); - match res { - Ok(tuple) => expected.push(tuple), - Err(_) => { - // couldn't fit that section; maybe another smaller section will fit - continue; - } - } - } - expected -} - -/// Populate a random number of sections with randomly chosen identities and random DEs -fn fill_encrypted_adv<'a, R: rand::Rng, C: CryptoProvider>( - mut rng: &mut R, - identities: &'a [TestIdentity<C>], - adv_builder: &mut AdvBuilder, -) -> Vec<SectionConfig<'a, C>> { - let mut expected = Vec::new(); - let mut salt_rng = C::CryptoRng::new(); - // build sections - for _ in 0..rng.gen_range(0..=6) { - let chosen_index = rng.gen_range(0..identities.len()); - let identity = &identities[chosen_index]; - - let broadcast_cm = identity.broadcast_credential(); - - let res = if rng.gen_bool(0.5) { - adv_builder - .section_builder(MicEncryptedSectionEncoder::<C>::new_random_salt( - &mut salt_rng, - identity.identity_type, - &broadcast_cm, - )) - .map(|s| { - SectionConfig::new( - Some(identity), - None, - Some(VerificationMode::Mic), - add_des(s, &mut rng), - ) - }) - } else { - adv_builder - .section_builder(SignedEncryptedSectionEncoder::<C>::new_random_salt( - &mut salt_rng, - identity.identity_type, - &broadcast_cm, - )) - .map(|s| { - SectionConfig::new( - Some(identity), - None, - Some(VerificationMode::Signature), - add_des(s, &mut rng), - ) - }) - }; - match res { - Ok(tuple) => expected.push(tuple), - Err(_) => { - // couldn't fit that section; maybe another smaller section will fit - continue; - } - } - } - expected -} - -struct TestIdentity<C: CryptoProvider> { - identity_type: EncryptedIdentityDataElementType, - key_seed: [u8; 32], - extended_metadata_key: MetadataKey, - key_pair: np_ed25519::KeyPair<C>, - marker: PhantomData<C>, -} -impl<C: CryptoProvider> TestIdentity<C> { - /// Generate a new identity with random crypto material - fn random<R: rand::Rng + rand::CryptoRng>(rng: &mut R) -> Self { - Self { - identity_type: *EncryptedIdentityDataElementType::iter() - .collect::<Vec<_>>() - .choose(rng) - .unwrap(), - key_seed: rng.gen(), - extended_metadata_key: MetadataKey(rng.gen()), - key_pair: np_ed25519::KeyPair::<C>::generate(), - marker: PhantomData, - } - } - /// Returns a (simple, signed) broadcast credential using crypto material from this identity - fn broadcast_credential(&self) -> SimpleSignedBroadcastCryptoMaterial { - SimpleSignedBroadcastCryptoMaterial::new( - self.key_seed, - self.extended_metadata_key, - self.key_pair.private_key(), - ) - } - /// Returns a discovery credential using crypto material from this identity - fn discovery_credential(&self) -> V1DiscoveryCredential { - self.broadcast_credential().derive_v1_discovery_credential::<C>() - } -} -/// Add several DEs with random types and contents -fn add_des<I: SectionEncoder, R: rand::Rng>( - mut sb: SectionBuilder<&mut AdvBuilder, I>, - rng: &mut R, -) -> Vec<GenericDataElement> { - let mut des = Vec::new(); - for _ in 0..rng.gen_range(0..=2) { - // not worried about multi byte type encoding here, so just sticking with what can sometimes - // fit in the 1-byte header, and isn't an identity element - let de_type = rng.gen_range(10_u32..=20); - // covers lengths that fit or don't fit in 3 bits (1 byte header) - let de_len = rng.gen_range(0..=10); - let mut de_data = vec![0; de_len]; - rng.fill(&mut de_data[..]); - let de = GenericDataElement::try_from(de_type.into(), &de_data).unwrap(); - if sb.add_de(|_| de.clone()).is_err() { - // no more room in the section - break; - } - des.push(de); - } - sb.add_to_advertisement(); - des -} -struct SectionConfig<'a, C: CryptoProvider> { - /// `Some` iff an encrypted identity should be used - identity: Option<&'a TestIdentity<C>>, - /// `Some` iff `identity` is `None` - plaintext_mode: Option<PlaintextIdentityMode>, - /// `Some` iff `identity` is `Some` - verification_mode: Option<VerificationMode>, - data_elements: Vec<GenericDataElement>, -} -impl<'a, C: CryptoProvider> SectionConfig<'a, C> { - pub fn new( - identity: Option<&'a TestIdentity<C>>, - plaintext_mode: Option<PlaintextIdentityMode>, - verification_mode: Option<VerificationMode>, - data_elements: Vec<GenericDataElement>, - ) -> Self { - Self { identity, plaintext_mode, verification_mode, data_elements } - } -}
diff --git a/nearby/presence/np_adv/src/deserialization_arena.rs b/nearby/presence/np_adv/src/deserialization_arena.rs index 9b58cbf..d0ab12e 100644 --- a/nearby/presence/np_adv/src/deserialization_arena.rs +++ b/nearby/presence/np_adv/src/deserialization_arena.rs
@@ -15,7 +15,7 @@ //! Types for creating arenas used in deserialization of np_adv. This implementation is purpose-made //! for deserializing in `np_adv` and is not intended for general use as an arena. -use crate::extended::BLE_ADV_SVC_CONTENT_LEN; +use crate::extended::BLE_5_ADV_SVC_MAX_CONTENT_LEN; /// Create a [`DeserializationArena`] suitable for use with deserializing an advertisement. #[macro_export] @@ -64,13 +64,13 @@ /// [`deserialization_arena!`][crate::deserialization_arena!] macro to create an instance. pub struct DeserializationArena<'a> { #[doc(hidden)] // Exposed for use by `deserialization_arena!` only. - pub buffer: &'a mut [u8; BLE_ADV_SVC_CONTENT_LEN], + pub buffer: &'a mut [u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN], } impl<'a> DeserializationArena<'a> { #[doc(hidden)] // Exposed for use by `deserialization_arena!` only. - pub fn new_buffer() -> [u8; BLE_ADV_SVC_CONTENT_LEN] { - [0; BLE_ADV_SVC_CONTENT_LEN] + pub fn new_buffer() -> [u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN] { + [0; BLE_5_ADV_SVC_MAX_CONTENT_LEN] } /// Convert this arena into an allocator that can start allocating. @@ -87,11 +87,11 @@ #[cfg(test)] mod test { - use crate::{deserialization_arena::ArenaOutOfSpace, extended::BLE_ADV_SVC_CONTENT_LEN}; + use crate::{deserialization_arena::ArenaOutOfSpace, extended::BLE_5_ADV_SVC_MAX_CONTENT_LEN}; #[test] fn test_creation() { - assert_eq!(BLE_ADV_SVC_CONTENT_LEN, deserialization_arena!().buffer.len()); + assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN, deserialization_arena!().buffer.len()); } #[test] @@ -99,7 +99,7 @@ let arena = deserialization_arena!(); let mut allocator = arena.into_allocator(); assert_eq!(Ok(&mut [0_u8; 100][..]), allocator.allocate(100)); - assert_eq!(BLE_ADV_SVC_CONTENT_LEN - 100, allocator.slice.len()); + assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 100, allocator.slice.len()); } #[test]
diff --git a/nearby/presence/np_adv/src/extended/data_elements/mod.rs b/nearby/presence/np_adv/src/extended/data_elements/mod.rs index 4e6e481..2989966 100644 --- a/nearby/presence/np_adv/src/extended/data_elements/mod.rs +++ b/nearby/presence/np_adv/src/extended/data_elements/mod.rs
@@ -17,13 +17,15 @@ //! Commonly used DEs have dedicated types (e.g. [TxPowerDataElement], etc), but if another DE is //! needed, [GenericDataElement] will allow constructing any type of DE. -use crate::extended::{ - de_type::DeType, - deserialize::DataElement, - serialize::{DeHeader, SingleTypeDataElement, WriteDataElement}, - DeLength, ENCRYPTION_INFO_DE_TYPE, MAX_DE_LEN, +use crate::{ + extended::{ + de_type::DeType, + deserialize::data_element::DataElement, + serialize::{DeHeader, SingleTypeDataElement, WriteDataElement}, + MAX_DE_LEN, + }, + shared_data::*, }; -use crate::shared_data::*; use array_view::ArrayView; use sink::Sink; @@ -138,54 +140,6 @@ ActionsTooLong, } -pub(crate) const SIGNATURE_ENCRYPTION_SCHEME: u8 = 0b00001000; -pub(crate) const MIC_ENCRYPTION_SCHEME: u8 = 0b00000000; - -/// Determines whether a signature or mic encryption scheme is used -pub(crate) struct EncryptionInfoDataElement { - /// First byte is bESSSSRRR where SSSS is the encryption scheme, rest are the salt - pub info: [u8; 17], -} - -impl SingleTypeDataElement for EncryptionInfoDataElement { - const DE_TYPE: DeType = ENCRYPTION_INFO_DE_TYPE; -} - -impl EncryptionInfoDataElement { - pub(crate) fn serialize(&self) -> [u8; 19] { - let mut buffer = [0_u8; 19]; - buffer[0..2].copy_from_slice(self.de_header().serialize().as_slice()); - buffer[2..19].copy_from_slice(&self.info); - buffer - } - - fn de_header(&self) -> DeHeader { - DeHeader::new( - Self::DE_TYPE, - DeLength { - len: self.info.len().try_into().expect("encryption info is a valid length"), - }, - ) - } - - /// Constructs the signature encryption scheme variant - pub fn signature(salt_bytes: &[u8; 16]) -> Self { - Self::new(SIGNATURE_ENCRYPTION_SCHEME, salt_bytes) - } - - /// Constructs the mic encryption scheme variant - pub fn mic(salt_bytes: &[u8; 16]) -> Self { - Self::new(MIC_ENCRYPTION_SCHEME, salt_bytes) - } - - fn new(scheme: u8, salt_bytes: &[u8; 16]) -> Self { - let mut sig_info = [0_u8; 17]; - sig_info[0] = scheme; - sig_info[1..].copy_from_slice(salt_bytes); - Self { info: sig_info } - } -} - /// Context sync sequence number pub struct ContextSyncSeqNumDataElement { num: ContextSyncSeqNum,
diff --git a/nearby/presence/np_adv/src/extended/data_elements/tests.rs b/nearby/presence/np_adv/src/extended/data_elements/tests.rs index 6f085cd..018f92c 100644 --- a/nearby/presence/np_adv/src/extended/data_elements/tests.rs +++ b/nearby/presence/np_adv/src/extended/data_elements/tests.rs
@@ -17,51 +17,52 @@ extern crate std; use super::*; -use crate::extended::serialize::AdvertisementType; -use crate::{ - extended::serialize::{section_tests::SectionBuilderExt, AdvBuilder, PublicSectionEncoder}, - shared_data::TxPower, -}; +use crate::extended::serialize::{section_tests::SectionBuilderExt, AdvBuilder}; +use crate::extended::serialize::{AdvertisementType, UnencryptedSectionEncoder}; +use crate::extended::V1_ENCODING_UNENCRYPTED; +use crypto_provider_default::CryptoProviderImpl; #[test] fn serialize_tx_power_de() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder.add_de_res(|_| TxPower::try_from(3_i8).map(TxPowerDataElement::from)).unwrap(); assert_eq!( &[ - 3, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 2, // section len 0x15, // len 1 type 0x05 3 ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } #[test] fn serialize_actions_de_empty() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder.add_de_res(|_| ActionsDataElement::try_from_actions(&[])).unwrap(); assert_eq!( &[ - 2, // section header - 0x03, // public identity - 0x06, // len 0 type 0x06 + V1_ENCODING_UNENCRYPTED, //header + 1, // section len + 0x06, // len 0 type 0x06 ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_actions_de_non_empty() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de_res(|_| ActionsDataElement::try_from_actions(&[1, 1, 2, 3, 5, 8])) @@ -69,19 +70,21 @@ assert_eq!( &[ - 8, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 7, // section len 0x66, // len 6 type 0x06 1, 1, 2, 3, 5, 8 // fibonacci, of course ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_context_sync_seq_num_de() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de_res(|_| ContextSyncSeqNum::try_from(3).map(ContextSyncSeqNumDataElement::from)) @@ -89,59 +92,65 @@ assert_eq!( &[ - 4, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 3, // section len 0x81, 0x13, // len 1 type 0x13 3, // seq num ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_connectivity_info_de_bluetooth() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder.add_de(|_| ConnectivityInfoDataElement::bluetooth([1; 4], [2; 6])).unwrap(); assert_eq!( &[ - 14, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 13, // section len 0x8B, 0x11, // len 11 type 0x11 1, // connectivity type 1, 1, 1, 1, // svc id 2, 2, 2, 2, 2, 2 // mac ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_connectivity_info_de_mdns() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder.add_de(|_| ConnectivityInfoDataElement::mdns([1; 4], 2)).unwrap(); assert_eq!( &[ - 9, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 8, // section len 0x86, 0x11, // len 11 type 0x11 2, // connectivity type 1, 1, 1, 1, // svc id 2 // port ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_connectivity_info_de_wifi_direct() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de(|_| ConnectivityInfoDataElement::wifi_direct([1; 10], [2; 10], [3; 2], 4)) @@ -149,8 +158,8 @@ assert_eq!( &[ - 27, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 26, // section len 0x98, 0x11, // len 24 type 0x11 3, // connectivity type 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // ssid @@ -158,14 +167,16 @@ 3, 3, // freq 4 // port ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } +#[rustfmt::skip] #[test] fn serialize_connectivity_capabilities_de_wifi_direct() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de(|_| ConnectivityCapabilityDataElement::wifi_direct([1; 3], [2; 3])) @@ -173,13 +184,46 @@ assert_eq!( &[ - 10, // section header - 0x03, // public identity + V1_ENCODING_UNENCRYPTED, + 9, // section len 0x87, 0x12, // len 7 type 0x12 2, // connectivity type 1, 1, 1, // supported 2, 2, 2, // connected ], - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } + +mod coverage_gaming { + use super::*; + use alloc::format; + #[test] + fn de_type_const_from() { + let _ = DeType::const_from(3); + } + + #[test] + fn template() {} + + #[test] + fn generic_de_error_derives() { + let err = GenericDataElementError::DataTooLong; + let _ = format!("{:?}", err); + assert_eq!(err, err); + } + + #[test] + fn actions_de_error_derives() { + let err = ActionsDataElementError::ActionsTooLong; + let _ = format!("{:?}", err); + assert_eq!(err, err); + } + + #[test] + fn generic_data_element_debug() { + let generic = + GenericDataElement::try_from(DeType::from(1000_u32), &[10, 11, 12, 13]).unwrap(); + let _ = format!("{:?}", generic); + } +}
diff --git a/nearby/presence/np_adv/src/extended/de_type.rs b/nearby/presence/np_adv/src/extended/de_type.rs index 975df90..baefe6a 100644 --- a/nearby/presence/np_adv/src/extended/de_type.rs +++ b/nearby/presence/np_adv/src/extended/de_type.rs
@@ -13,10 +13,9 @@ // limitations under the License. //! V1 DE type types -use crate::de_type::{EncryptedIdentityDataElementType, IdentityDataElementType}; /// Data element types for extended advertisements -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct DeType { // 4 billion type codes should be enough for anybody code: u32, @@ -52,98 +51,13 @@ } } -pub(crate) trait ExtendedDataElementType: Sized { - /// A type code for use in the DE header. - fn type_code(&self) -> DeType; - /// Returns the matching type for the code, else `None` - fn from_type_code(de_type: DeType) -> Option<Self>; -} - -impl ExtendedDataElementType for IdentityDataElementType { - fn type_code(&self) -> DeType { - DeType::from(self.shared_type_code()) - } - - fn from_type_code(de_type: DeType) -> Option<Self> { - de_type.code.try_into().ok().and_then(Self::from_shared_type_code) - } -} - -impl ExtendedDataElementType for EncryptedIdentityDataElementType { - fn type_code(&self) -> DeType { - DeType::from(self.as_identity_data_element_type().shared_type_code()) - } - - fn from_type_code(code: DeType) -> Option<Self> { - IdentityDataElementType::from_type_code(code) - .and_then(|idet| idet.as_encrypted_identity_de_type()) - } -} - #[cfg(test)] -mod tests { - extern crate std; - - use super::*; - use std::{collections, fmt}; +mod test { + use crate::extended::de_type::DeType; #[test] - fn identity_type_codes_are_consistent() { - de_type_codes_are_consistent::<IdentityDataElementType>() - } - - #[test] - fn encrypted_identity_type_codes_are_consistent() { - de_type_codes_are_consistent::<EncryptedIdentityDataElementType>() - } - - #[test] - fn identity_type_codes_are_distinct() { - de_distinct_type_codes::<IdentityDataElementType>() - } - - #[test] - fn encrypted_identity_type_codes_are_distinct() { - de_distinct_type_codes::<EncryptedIdentityDataElementType>() - } - - #[test] - fn identity_no_accidentally_mapped_type_codes() { - de_no_accidentally_mapped_type_codes::<IdentityDataElementType>() - } - - #[test] - fn encrypted_identity_no_accidentally_mapped_type_codes() { - de_no_accidentally_mapped_type_codes::<EncryptedIdentityDataElementType>() - } - - fn de_type_codes_are_consistent< - D: PartialEq + fmt::Debug + ExtendedDataElementType + strum::IntoEnumIterator, - >() { - for det in D::iter() { - let actual = D::from_type_code(det.type_code()); - assert_eq!(Some(det), actual) - } - } - - fn de_distinct_type_codes< - D: PartialEq + fmt::Debug + ExtendedDataElementType + strum::IntoEnumIterator, - >() { - let codes = D::iter().map(|det| det.type_code()).collect::<collections::HashSet<_>>(); - assert_eq!(codes.len(), D::iter().count()); - } - - fn de_no_accidentally_mapped_type_codes< - D: PartialEq + fmt::Debug + ExtendedDataElementType + strum::IntoEnumIterator, - >() { - let codes = D::iter().map(|det| det.type_code()).collect::<collections::HashSet<_>>(); - // not going to try all 4 billion possibilities, but we can make an effort - for possible_code in 0_u32..100_000 { - if codes.contains(&possible_code.into()) { - continue; - } - - assert_eq!(None, D::from_type_code(possible_code.into())); - } + fn u32_from_de_type() { + let de = DeType::from(8u32); + let _val: u32 = de.into(); } }
diff --git a/nearby/presence/np_adv/src/extended/deserialize/data_element/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/data_element/mod.rs new file mode 100644 index 0000000..e717fa1 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/data_element/mod.rs
@@ -0,0 +1,260 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Parsing logic for V1 data elements, header + contents + +use crate::extended::{de_requires_extended_bit, de_type::DeType, deserialize, DeLength}; +use array_view::ArrayView; +use nom::{branch, bytes, combinator, error, number, sequence}; +use np_hkdf::v1_salt; + +#[cfg(test)] +mod tests; + +/// A deserialized data element in a section. +/// +/// The DE has been processed to the point of exposing a DE type and its contents as a `&[u8]`, but +/// no DE-type-specific processing has been performed. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DataElement<'adv> { + offset: v1_salt::DataElementOffset, + de_type: DeType, + contents: &'adv [u8], +} + +impl<'adv> DataElement<'adv> { + pub(crate) fn new( + offset: v1_salt::DataElementOffset, + de_type: DeType, + contents: &'adv [u8], + ) -> Self { + Self { offset, de_type, contents } + } +} + +impl DeHeader { + pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], DeHeader> { + // 1-byte header: 0b0LLLTTTT + let parse_single_byte_de_header = + combinator::map_opt::<&[u8], _, DeHeader, error::Error<&[u8]>, _, _>( + combinator::consumed(combinator::map_res( + combinator::verify(number::complete::u8, |&b| !deserialize::hi_bit_set(b)), + |b| { + // L bits + let len = (b >> 4) & 0x07; + // T bits + let de_type = ((b & 0x0F) as u32).into(); + + len.try_into().map(|l| (l, de_type)) + }, + )), + |(header_bytes, (len, de_type))| { + ArrayView::try_from_slice(header_bytes).map(|header_bytes| DeHeader { + header_bytes, + contents_len: len, + de_type, + }) + }, + ); + + // multi-byte headers: 0b1LLLLLLL (0b1TTTTTTT)* 0b0TTTTTTT + // leading 1 in first byte = multibyte format + // leading 1 in subsequent bytes = there is at least 1 more type bytes + // leading 0 = this is the last header byte + // 127-bit length, effectively infinite type bit length + + // It's conceivable to have non-canonical extended type sequences where 1 or more leading + // bytes don't have any bits set (other than the marker hi bit), thereby contributing nothing + // to the final value. + // To prevent that, we require that either there be only 1 type byte, or that the first of the + // multiple type bytes must have a value bit set. It's OK to have no value bits in subsequent + // type bytes. + + let parse_ext_de_header = combinator::verify( + combinator::map_opt( + combinator::consumed(sequence::pair( + // length byte w/ leading 1 + combinator::map_res( + combinator::verify(number::complete::u8::<&[u8], _>, |&b| { + deserialize::hi_bit_set(b) + }), + // snag the lower 7 bits + |b| (b & 0x7F).try_into(), + ), + branch::alt(( + // 1 type byte case + combinator::recognize( + // 0-hi-bit type code byte + combinator::verify(number::complete::u8, |&b| { + !deserialize::hi_bit_set(b) + }), + ), + // multiple type byte case: leading type byte must have at least 1 value bit + combinator::recognize(sequence::tuple(( + // hi bit and at least 1 value bit, otherwise it would be non-canonical + combinator::verify(number::complete::u8, |&b| { + deserialize::hi_bit_set(b) && (b & 0x7F != 0) + }), + // 0-3 1-hi-bit type code bytes with any bit pattern. Max is 3 since two 7 + // bit type chunks are processed before and after this, for a total of 5, + // and that's as many 7-bit chunks as are needed to support a 32-bit type. + bytes::complete::take_while_m_n(0, 3, deserialize::hi_bit_set), + // final 0-hi-bit type code byte + combinator::verify(number::complete::u8, |&b| { + !deserialize::hi_bit_set(b) + }), + ))), + )), + )), + |(header_bytes, (len, type_bytes))| { + // snag the low 7 bits of each type byte and accumulate + type_bytes + .iter() + .try_fold(0_u64, |accum, b| { + accum.checked_shl(7).map(|n| n + ((b & 0x7F) as u64)) + }) + .and_then(|type_code| u32::try_from(type_code).ok()) + .and_then(|type_code| { + ArrayView::try_from_slice(header_bytes).map(|header_bytes| DeHeader { + header_bytes, + contents_len: len, + de_type: type_code.into(), + }) + }) + }, + ), + |header| { + // verify that the length and type code actually require use of the extended bit + de_requires_extended_bit(header.de_type.as_u32(), header.contents_len.len) + }, + ); + + branch::alt((parse_single_byte_de_header, parse_ext_de_header))(input) + } +} + +impl<'adv> DataElement<'adv> { + /// The offset of the DE in its containing Section. + /// + /// Used with the section salt to derive per-DE salt. + pub fn offset(&self) -> v1_salt::DataElementOffset { + self.offset + } + /// The type of the DE + pub fn de_type(&self) -> DeType { + self.de_type + } + /// The contents of the DE + pub fn contents(&self) -> &'adv [u8] { + self.contents + } +} + +/// An iterator that parses the given data elements iteratively. In environments where memory is +/// not severely constrained, it is usually safer to collect this into `Result<Vec<DataElement>>` +/// so the validity of the whole advertisement can be checked before proceeding with further +/// processing. +#[derive(Debug)] +pub struct DataElementParsingIterator<'adv> { + input: &'adv [u8], + // The index of the data element this is currently at + offset: u8, +} + +impl<'adv> DataElementParsingIterator<'adv> { + pub(crate) fn new(input: &'adv [u8]) -> Self { + Self { input, offset: 0 } + } +} + +impl<'adv> Iterator for DataElementParsingIterator<'adv> { + type Item = Result<DataElement<'adv>, DataElementParseError>; + + fn next(&mut self) -> Option<Self::Item> { + match ProtoDataElement::parse(self.input) { + Ok((rem, pde)) => { + self.input = rem; + let current_offset = self.offset; + self.offset = if let Some(offset) = self.offset.checked_add(1) { + offset + } else { + return Some(Err(DataElementParseError::TooManyDataElements)); + }; + Some(Ok(pde.into_data_element(v1_salt::DataElementOffset::from(current_offset)))) + } + Err(nom::Err::Failure(e)) => Some(Err(DataElementParseError::NomError(e.code))), + Err(nom::Err::Incomplete(_)) => { + panic!("Should always complete since we are parsing using the `nom::complete` APIs") + } + Err(nom::Err::Error(_)) => { + // nom `Error` is recoverable, it usually means we should move on the parsing the + // next section. There is nothing after data elements within a section, so we just + // check that there is no remaining data. + if !self.input.is_empty() { + return Some(Err(DataElementParseError::UnexpectedDataAfterEnd)); + } + None + } + } + } +} + +/// The error that may arise while parsing data elements. +#[derive(Debug, PartialEq, Eq)] +pub enum DataElementParseError { + /// Unexpected data found after the end of the data elements portion. This means either the + /// parser was fed with additional data (it should only be given the bytes within a section, + /// not the whole advertisement), or the length field in the header of the data element is + /// malformed. + UnexpectedDataAfterEnd, + /// There are too many data elements in the advertisement. The maximum number supported by the + /// current parsing logic is 255. + TooManyDataElements, + /// A parse error is returned during nom. + NomError(error::ErrorKind), +} + +/// Deserialize-specific version of a DE header that incorporates the header length. +/// This is needed for encrypted identities that need to construct a slice of everything in the +/// section following the identity DE header. +#[derive(Debug, PartialEq, Eq, Clone)] +pub(crate) struct DeHeader { + /// The original bytes of the header, at most 6 bytes long (1 byte len, 5 bytes type) + pub(crate) header_bytes: ArrayView<u8, 6>, + pub(crate) de_type: DeType, + pub(crate) contents_len: DeLength, +} + +/// An intermediate stage in parsing a [DataElement] that lacks `offset`. +#[derive(Debug, PartialEq, Eq)] +pub struct ProtoDataElement<'d> { + header: DeHeader, + /// `len()` must equal `header.contents_len` + contents: &'d [u8], +} + +impl<'d> ProtoDataElement<'d> { + pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], ProtoDataElement> { + let (remaining, header) = DeHeader::parse(input)?; + let len = header.contents_len; + combinator::map(bytes::complete::take(len.as_u8()), move |slice| { + let header_clone = header.clone(); + ProtoDataElement { header: header_clone, contents: slice } + })(remaining) + } + + fn into_data_element(self, offset: v1_salt::DataElementOffset) -> DataElement<'d> { + DataElement::new(offset, self.header.de_type, self.contents) + } +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/data_element/tests.rs b/nearby/presence/np_adv/src/extended/deserialize/data_element/tests.rs new file mode 100644 index 0000000..473cf37 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/data_element/tests.rs
@@ -0,0 +1,348 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +use super::*; +use alloc::{vec, vec::Vec}; + +#[test] +fn parse_de_single_byte_header_length_overrun() { + // length 7, type 0x03 + let input = [0b0111_0011, 0x01, 0x02]; + assert_eq!( + nom::Err::Error(error::Error { + // attempted to read DE contents + input: &input.as_slice()[1..], + code: error::ErrorKind::Eof, + }), + ProtoDataElement::parse(&input).unwrap_err() + ); +} + +#[test] +fn parse_de_multi_byte_header_length_overrun() { + let input = [0b1000_0111, 0x1F, 0x01, 0x02]; + assert_eq!( + nom::Err::Error(error::Error { + // attempted to read DE contents + input: &input.as_slice()[2..], + code: error::ErrorKind::Eof, + }), + ProtoDataElement::parse(&input).unwrap_err() + ); +} + +#[test] +fn parse_de_with_1_byte_header() { + let data = [0x51, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[6..], + ProtoDataElement { + header: DeHeader { + de_type: 1_u8.into(), + header_bytes: ArrayView::try_from_slice(&[0x51]).unwrap(), + contents_len: 5_u8.try_into().unwrap(), + }, + contents: &data[1..6], + } + )), + ProtoDataElement::parse(&data) + ); +} + +#[test] +fn parse_de_with_2_byte_header() { + let data = [0x85, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[7..], + ProtoDataElement { + header: DeHeader { + de_type: 16_u8.into(), + header_bytes: ArrayView::try_from_slice(&[0x85, 0x10]).unwrap(), + contents_len: 5_u8.try_into().unwrap(), + }, + contents: &data[2..7], + } + )), + ProtoDataElement::parse(&data) + ); +} + +#[test] +fn parse_de_with_3_byte_header() { + let data = [0x85, 0xC1, 0x41, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[8..], + ProtoDataElement { + header: DeHeader { + header_bytes: ArrayView::try_from_slice(&[0x85, 0xC1, 0x41]).unwrap(), + contents_len: 5_u8.try_into().unwrap(), + de_type: 0b0000_0000_0000_0000_0010_0000_1100_0001_u32.into(), + }, + contents: &data[3..8], + } + )), + ProtoDataElement::parse(&data) + ); +} + +#[test] +fn parse_de_header_1_byte() { + let data = [0x51, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[1..], + DeHeader { + de_type: 1_u8.into(), + contents_len: 5_u8.try_into().unwrap(), + header_bytes: ArrayView::try_from_slice(&[0x51]).unwrap(), + } + )), + DeHeader::parse(&data) + ); +} + +#[test] +fn parse_de_header_2_bytes() { + let data = [0x88, 0x01]; + assert_eq!( + Ok(( + &data[2..], + DeHeader { + de_type: 1_u8.into(), + contents_len: 8_u8.try_into().unwrap(), + header_bytes: ArrayView::try_from_slice(&[0x88, 0x01]).unwrap(), + } + )), + DeHeader::parse(&data) + ); +} + +#[test] +fn parse_de_header_3_bytes() { + let data = [0x83, 0xC1, 0x41, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[3..], + DeHeader { + de_type: 0b0000_0000_0000_0000_0010_0000_1100_0001_u32.into(), + contents_len: 3_u8.try_into().unwrap(), + header_bytes: ArrayView::try_from_slice(&[0x83, 0xC1, 0x41]).unwrap(), + } + )), + DeHeader::parse(&data) + ); +} + +#[test] +fn parse_de_header_4_bytes() { + let data = [0x83, 0xC1, 0xC1, 0x41, 0xFF, 0xFF]; + assert_eq!( + Ok(( + &data[4..], + DeHeader { + de_type: 0b0000_0000_0001_0000_0110_0000_1100_0001_u32.into(), + contents_len: 3_u8.try_into().unwrap(), + header_bytes: ArrayView::try_from_slice(&[0x83, 0xC1, 0xC1, 0x41]).unwrap(), + } + )), + DeHeader::parse(&data) + ); +} + +#[test] +fn parse_de_header_max_length_extension() { + // 1 byte length + 5 bytes of type is the max possible length of an extended DE header. + // The first 3 bits of type will be discarded by the left shift, so if an extended DE header + // does make it to 5 bytes, we will only read the least significant 32 bits out of a possible 35. + // The contents of the most significant 3 bits of type code must be 0's, otherwise the adv will + // be discarded + let data = [0x80, 0x8F, 0xFF, 0xFF, 0xFF, 0x7F]; + assert_eq!( + Ok(( + &data[6..], + DeHeader { + de_type: u32::MAX.into(), + contents_len: 0_u8.try_into().unwrap(), + header_bytes: ArrayView::try_from_slice(&[0x80, 0x8F, 0xFF, 0xFF, 0xFF, 0x7F]) + .unwrap(), + } + )), + DeHeader::parse(&data) + ); +} + +// In a 6 byte extended de header, if any bits are non-zero in the most 3 significant bits of type, +// the parsing will fail as this would be out of range of a valid u32 value. +#[test] +fn parse_de_6_byte_header_invalid_significant_bits() { + assert!(DeHeader::parse(&[0x80, 0x9F, 0xFF, 0xFF, 0xFF, 0x7F]).is_err()); + assert!(DeHeader::parse(&[0x80, 0xCF, 0xFF, 0xFF, 0xFF, 0x7F]).is_err()); + assert!(DeHeader::parse(&[0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]).is_err()); +} + +#[test] +fn parse_de_header_over_max_length_extension() { + // last header byte cannot contain a leading 1 + let data = [0x80, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF]; + assert_eq!( + nom::Err::Error(error::Error { + // failed parsing the last byte + input: &data.as_slice()[5..], + code: error::ErrorKind::Verify, + }), + DeHeader::parse(&data).unwrap_err() + ); +} + +// Test edge cases which can be represented in fewer bytes +#[test] +fn parse_de_header_invalid_multi_byte_type_code() { + // extended length and type codes which can be represented in a single byte + assert!(DeHeader::parse(&[0b1000_0000, 0b000_0000]).is_err()); + assert!(DeHeader::parse(&[0b1000_0000, 0b000_0001]).is_err()); + assert!(DeHeader::parse(&[0b1000_0111, 0b000_1111]).is_err()); + + // first byte of type doesn't have any bits in it so it contributes nothing + assert!(DeHeader::parse(&[0b1000_0111, 0b1000_0000, 0b0100_0000]).is_err()); + // first 2 bytes of type are unnecessary + assert!(DeHeader::parse(&[0b1000_0001, 0b1000_0000, 0b1000_0000, 0b1100_0000]).is_err()); + + // extended bit set with no following byte + assert!(DeHeader::parse(&[0b1000_0001, 0b1000_0000]).is_err()); + + // needs one extra bit of length so must use extended + assert!(DeHeader::parse(&[0b100_1111, 0b000_1111]).is_ok()); + + // needs one extra bit of type so must use extended + assert!(DeHeader::parse(&[0b100_0111, 0b001_1111]).is_ok()); + + // valid to trail with all 0's for a larger type code + assert!(DeHeader::parse(&[0b100_1111, 0b1000_0001, 0b0000_0000]).is_ok()); + + // valid to trail with all 0's in middle of type code + assert!(DeHeader::parse(&[0b100_1111, 0b1000_0001, 0b1000_0000, 0b0000_0001]).is_ok()); +} + +#[test] +fn de_iteration_exposes_correct_data() { + let mut de_data = vec![]; + // de 1 byte header, type 5, len 5 + de_data.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 16, len 1 + de_data.extend_from_slice(&[0x81, 0x10, 0x01]); + + let iterator = DataElementParsingIterator::new(&de_data); + let des = iterator.collect::<Result<Vec<_>, _>>().unwrap(); + + assert_eq!( + vec![ + DataElement::new(0.into(), 5_u32.into(), &[0x01, 0x02, 0x03, 0x04, 0x05]), + DataElement::new(1.into(), 16_u32.into(), &[0x01]), + ], + des + ); +} + +#[test] +fn de_iteration_single_de() { + let mut de_data = vec![]; + // de 2 byte header, type 16, len 1 + de_data.extend_from_slice(&[0x81, 0x10, 0x01]); + + let iterator = DataElementParsingIterator::new(&de_data); + let des = iterator.collect::<Result<Vec<_>, _>>().unwrap(); + + assert_eq!(vec![DataElement::new(0.into(), 16_u32.into(), &[0x01]),], des); +} + +#[test] +fn de_iteration_single_de_empty_contents() { + let mut de_data = vec![]; + // de 1 byte header, type 1, len 0 + de_data.extend_from_slice(&[0x01]); + + let iterator = DataElementParsingIterator::new(&de_data); + let des = iterator.collect::<Result<Vec<_>, _>>().unwrap(); + + assert_eq!(vec![DataElement::new(0.into(), 1_u32.into(), &[])], des); +} + +#[test] +fn de_iteration_max_number_des() { + let mut de_data = vec![]; + // de 1 byte header, type 1, len 0 + // add this 255 times which is the max amount of + // supported DEs in a single section + for _ in 0..255 { + de_data.extend_from_slice(&[0x01]); + } + + let iterator = DataElementParsingIterator::new(&de_data); + assert!(iterator.collect::<Result<Vec<_>, _>>().is_ok()); +} + +#[test] +fn de_iteration_over_max_number_des() { + let mut de_data = vec![]; + // de 1 byte header, type 1, len 0 + // add this 256 times to exceed max number of des in a section + for _ in 0..256 { + de_data.extend_from_slice(&[0x01]); + } + + let iterator = DataElementParsingIterator::new(&de_data); + assert_eq!( + iterator.collect::<Result<Vec<_>, _>>(), + Err(DataElementParseError::TooManyDataElements) + ); +} + +#[test] +fn de_parse_error_invalid_length_header() { + let mut de_data = vec![]; + // de 1 byte header, type 1, len 2, but only one byte left to process + de_data.extend_from_slice(&[0x21, 0x00]); + + let iterator = DataElementParsingIterator::new(&de_data); + assert_eq!( + iterator.collect::<Result<Vec<_>, _>>(), + Err(DataElementParseError::UnexpectedDataAfterEnd) + ); +} + +mod coverage_gaming { + use super::*; + use alloc::format; + + #[allow(clippy::clone_on_copy)] + #[test] + fn data_element_debug_and_clone() { + let de = DataElement::new(0.into(), 0_u32.into(), &[]); + let _ = format!("{:?}", de); + let _ = de.clone(); + let iterator = DataElementParsingIterator::new(&[]); + let _ = format!("{:?}", iterator); + let _ = format!("{:?}", DataElementParseError::TooManyDataElements); + let (_, header) = DeHeader::parse(&[0x11, 0xFF]).unwrap(); + let _ = format!("{:?}", header); + let _ = header.clone(); + let (_, pde) = ProtoDataElement::parse(&[0x11, 0xFF]).unwrap(); + let _ = format!("{:?}", pde); + } +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/dev_tools.rs b/nearby/presence/np_adv/src/extended/deserialize/dev_tools.rs new file mode 100644 index 0000000..e77e083 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/dev_tools.rs
@@ -0,0 +1,87 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::fmt::Debug; + +use crate::deserialization_arena::DeserializationArena; +use array_view::ArrayView; +use crypto_provider::CryptoProvider; + +use crate::extended::deserialize::section::intermediate::{ + parse_sections, CiphertextSection, IntermediateSection, +}; +use crate::extended::NP_ADV_MAX_SECTION_LEN; +use crate::{credential::book::CredentialBook, header::V1AdvHeader}; + +/// Error in decryption operations for `deser_decrypt_v1_section_bytes_for_dev_tools`. +#[derive(Debug, Clone)] +pub enum AdvDecryptionError { + /// Cannot decrypt because the input section is not encrypted. + InputNotEncrypted, + /// Error parsing the given section. + ParseError, + /// No suitable credential found to decrypt the given section. + NoMatchingCredentials, +} + +/// The encryption scheme used for a V1 advertisement. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum V1EncryptionScheme { + /// Indicates MIC-based encryption and verification. + Mic, + /// Indicates signature-based encryption and verification. + Signature, +} + +/// Decrypt, but do not further deserialize the v1 bytes, intended for developer tooling uses only. +/// Production uses should use [crate::deserialize_advertisement] instead, which deserializes to a +/// structured format and provides extra type safety. +pub fn deser_decrypt_v1_section_bytes_for_dev_tools<'adv, 'cred, B, P>( + arena: DeserializationArena<'adv>, + cred_book: &'cred B, + header_byte: u8, + section_bytes: &'adv [u8], +) -> Result<(ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, V1EncryptionScheme), AdvDecryptionError> +where + B: CredentialBook<'cred>, + P: CryptoProvider, +{ + let header = V1AdvHeader::new(header_byte); + let int_sections = + parse_sections(header, section_bytes).map_err(|_| AdvDecryptionError::ParseError)?; + let cipher_section = match &int_sections[0] { + IntermediateSection::Plaintext(_) => Err(AdvDecryptionError::InputNotEncrypted)?, + IntermediateSection::Ciphertext(section) => section, + }; + + let mut allocator = arena.into_allocator(); + for (crypto_material, _) in cred_book.v1_iter() { + if let Some(plaintext) = cipher_section + .try_resolve_identity_and_decrypt::<_, P>(&mut allocator, &crypto_material) + { + let pt = plaintext.expect(concat!( + "Should not run out of space because DeserializationArenaAllocator is big ", + "enough to hold a single advertisement, and we exit immediately upon ", + "successful decryption", + )); + + let encryption_scheme = match cipher_section { + CiphertextSection::SignatureEncrypted(_) => V1EncryptionScheme::Signature, + CiphertextSection::MicEncrypted(_) => V1EncryptionScheme::Mic, + }; + return Ok((pt, encryption_scheme)); + } + } + Err(AdvDecryptionError::NoMatchingCredentials) +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs deleted file mode 100644 index b172db6..0000000 --- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mic_decrypt_tests.rs +++ /dev/null
@@ -1,471 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use super::*; -use crate::deserialization_arena; -use crate::extended::data_elements::TxPowerDataElement; -use crate::extended::deserialize::DataElementParseError; -use crate::extended::serialize::{AdvertisementType, SingleTypeDataElement, WriteDataElement}; -use crate::shared_data::TxPower; -use crate::{ - credential::{v1::V1, SimpleBroadcastCryptoMaterial}, - de_type::EncryptedIdentityDataElementType, - extended::{ - deserialize::{ - encrypted_section::{ - EncryptedSectionContents, IdentityResolutionOrDeserializationError, - MicVerificationError, - }, - parse_sections, - test_stubs::IntermediateSectionExt, - CiphertextSection, DataElement, RawV1Salt, - }, - serialize::{AdvBuilder, CapacityLimitedVec, MicEncryptedSectionEncoder}, - }, - parse_adv_header, AdvHeader, Section, -}; -use crypto_provider_default::CryptoProviderImpl; -use np_hkdf::v1_salt::DataElementOffset; -use sink::Sink; -use std::{prelude::rust_2021::*, vec}; - -#[test] -fn deserialize_mic_encrypted_correct_keys() { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let raw_salt = RawV1Salt([3; 16]); - let section_salt = V1Salt::<CryptoProviderImpl>::from(raw_salt); - let identity_type = EncryptedIdentityDataElementType::Private; - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); - - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - raw_salt, - &broadcast_cm, - )) - .unwrap(); - - let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap()); - section_builder.add_de(|_| txpower_de.clone()).unwrap(); - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let adv_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(adv_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - - let contents = if let CiphertextSection::MicEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - let keypair = np_ed25519::KeyPair::<CryptoProviderImpl>::generate(); - - // deserializing to Section works - let discovery_credential = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, keypair.private_key()) - .derive_v1_discovery_credential::<CryptoProviderImpl>(); - - let identity_resolution_material = - discovery_credential.unsigned_identity_resolution_material::<CryptoProviderImpl>(); - let verification_material = - discovery_credential.unsigned_verification_material::<CryptoProviderImpl>(); - - let arena = deserialization_arena!(); - let mut allocator = arena.into_allocator(); - let section = contents - .try_resolve_identity_and_deserialize::<CryptoProviderImpl>( - &mut allocator, - &identity_resolution_material, - &verification_material, - ) - .unwrap(); - - assert_eq!( - DecryptedSection::new( - EncryptedIdentityDataElementType::Private, - VerificationMode::Mic, - metadata_key, - raw_salt, - SectionContents { - section_header: 19 // encryption info de - + 2 // de header - + 16 // metadata key - + 2 // de contents - + 16, // mic hmac tag - // battery DE - data_element_start_offset: 2, - de_region_excl_identity: &[txpower_de.de_header().serialize().as_slice(), &[5],] - .concat(), - } - ), - section - ); - let data_elements = section.collect_data_elements().unwrap(); - assert_eq!( - data_elements, - &[DataElement { offset: 2.into(), de_type: 0x05_u8.into(), contents: &[5] }] - ); - - assert_eq!( - vec![(DataElementOffset::from(2_u8), TxPowerDataElement::DE_TYPE, vec![5_u8])], - data_elements - .into_iter() - .map(|de| (de.offset(), de.de_type(), de.contents().to_vec())) - .collect::<Vec<_>>() - ); - - let mut encryption_info_bytes = [0_u8; 19]; - encryption_info_bytes[0..2].copy_from_slice(&[0x91, 0x10]); - encryption_info_bytes[2] = 0x00; - encryption_info_bytes[3..].copy_from_slice(section_salt.as_slice()); - - let ciphertext_end = adv.as_slice().len() - 16; - assert_eq!( - &MicEncryptedSection { - contents: EncryptedSectionContents { - section_header: 19 // encryption info de - + 2 // de header - + 16 // metadata key - + 2 // de contents - + 16, // mic hmac tag - adv_header, - encryption_info: EncryptionInfo { bytes: encryption_info_bytes }, - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x1], - offset: 1.into(), - identity_type: EncryptedIdentityDataElementType::Private, - }, - all_ciphertext: &adv.as_slice()[1 + 1 + 19 + 2..ciphertext_end], - }, - mic: SectionMic { mic: adv.as_slice()[ciphertext_end..].try_into().unwrap() } - }, - contents - ); - - // plaintext is correct - { - let identity_resolution_contents = - contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>(); - let identity_match = identity_resolution_contents - .try_match::<CryptoProviderImpl>( - &identity_resolution_material.into_raw_resolution_material(), - ) - .unwrap(); - let arena = deserialization_arena!(); - let mut allocator = arena.into_allocator(); - let decrypted = contents - .contents - .decrypt_ciphertext::<CryptoProviderImpl>(&mut allocator, identity_match) - .unwrap(); - - let mut expected = Vec::new(); - // battery de - expected.extend_from_slice(txpower_de.clone().de_header().serialize().as_slice()); - let _ = txpower_de.write_de_contents(&mut expected); - - assert_eq!(metadata_key, decrypted.metadata_key_plaintext); - assert_eq!(&expected, decrypted.plaintext_contents); - } -} - -#[test] -fn deserialize_mic_encrypted_incorrect_aes_key_error() { - // bad aes key -> bad metadata key plaintext - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - Some([0xFF; 16].into()), - None, - None, - None, - ); -} - -#[test] -fn deserialize_mic_encrypted_incorrect_metadata_key_hmac_key_error() { - // bad metadata key hmac key -> bad calculated metadata key mac - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - None, - Some([0xFF; 32].into()), - None, - None, - ); -} - -#[test] -fn deserialize_mic_encrypted_incorrect_mic_hmac_key_error() { - // bad mic hmac key -> bad calculated mic - do_bad_deserialize_params::<CryptoProviderImpl>( - MicVerificationError::MicMismatch.into(), - None, - None, - Some([0xFF; 32].into()), - None, - ); -} - -#[test] -fn deserialize_mic_encrypted_incorrect_expected_metadata_key_hmac_error() { - // bad expected metadata key mac - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - None, - None, - None, - Some([0xFF; 32]), - ); -} - -#[test] -fn deserialize_mic_encrypted_incorrect_salt_error() { - // bad salt -> bad iv -> bad metadata key plaintext - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - ), - |_| {}, - |adv| adv[23..39].copy_from_slice(&[0xFF; 16]), - ); -} - -#[test] -fn deserialize_mic_encrypted_de_that_wont_parse() { - // add an extra byte to the section, leading it to try to parse a DE that doesn't exist - do_bad_deserialize_tampered( - DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd), - |sec| sec.try_push(0xFF).unwrap(), - |_| {}, - ); -} - -#[test] -fn deserialize_mic_encrypted_tampered_mic_error() { - // flip the a bit in the first MIC byte - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - MicVerificationError::MicMismatch.into(), - ), - |_| {}, - |adv| { - let mic_start = adv.len() - 16; - adv[mic_start] ^= 0x01 - }, - ); -} - -#[test] -fn deserialize_mic_encrypted_tampered_payload_error() { - // flip the last payload bit - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - MicVerificationError::MicMismatch.into(), - ), - |_| {}, - |adv| *adv.last_mut().unwrap() ^= 0x01, - ); -} - -/// Attempt a decryption that will fail when using the provided parameters for decryption only. -/// `None` means use the correct value for that parameter. -fn do_bad_deserialize_params<C: CryptoProvider>( - error: IdentityResolutionOrDeserializationError<MicVerificationError>, - aes_key: Option<crypto_provider::aes::Aes128Key>, - metadata_key_hmac_key: Option<np_hkdf::NpHmacSha256Key<C>>, - mic_hmac_key: Option<np_hkdf::NpHmacSha256Key<C>>, - expected_metadata_key_hmac: Option<[u8; 32]>, -) { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let section_salt: V1Salt<C> = [3; 16].into(); - let identity_type = EncryptedIdentityDataElementType::Private; - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::new(&key_seed); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); - - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<C>::new( - identity_type, - section_salt.into(), - &broadcast_cm, - )) - .unwrap(); - - section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap(); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - let contents = if let CiphertextSection::MicEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - let unsigned_identity_resolution_material = SectionIdentityResolutionMaterial { - aes_key: aes_key.unwrap_or_else(|| np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf)), - metadata_key_hmac_key: *metadata_key_hmac_key - .unwrap_or_else(|| key_seed_hkdf.extended_unsigned_metadata_key_hmac_key()) - .as_bytes(), - expected_metadata_key_hmac: expected_metadata_key_hmac.unwrap_or_else(|| { - key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0) - }), - }; - let identity_resolution_material = - UnsignedSectionIdentityResolutionMaterial::from_raw(unsigned_identity_resolution_material); - - let verification_material = UnsignedSectionVerificationMaterial { - mic_hmac_key: *mic_hmac_key - .unwrap_or_else(|| np_hkdf::UnsignedSectionKeys::hmac_key(&key_seed_hkdf)) - .as_bytes(), - }; - - assert_eq!( - error, - contents - .try_resolve_identity_and_deserialize::<C>( - &mut deserialization_arena!().into_allocator(), - &identity_resolution_material, - &verification_material, - ) - .unwrap_err() - ); -} - -#[derive(Debug, PartialEq)] -enum DeserializeError { - IdentityResolutionOrDeserializationError( - IdentityResolutionOrDeserializationError<MicVerificationError>, - ), - DataElementParseError(DataElementParseError), -} - -fn do_bad_deserialize_tampered( - expected_error: DeserializeError, - mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), - mangle_adv: impl Fn(&mut Vec<u8>), -) { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let section_salt: V1Salt<CryptoProviderImpl> = [3; 16].into(); - let identity_type = EncryptedIdentityDataElementType::Private; - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); - - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - section_salt.into(), - &broadcast_cm, - )) - .unwrap(); - - section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap(); - - mangle_section(&mut section_builder.section); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - let mut adv_mut = adv.as_slice().to_vec(); - mangle_adv(&mut adv_mut); - - let (remaining, header) = parse_adv_header(&adv_mut).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - let contents = if let CiphertextSection::MicEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - // generate a random key pair since we need _some_ public key in our discovery - // credential, even if it winds up going unused - let key_pair = np_ed25519::KeyPair::<CryptoProviderImpl>::generate(); - - let discovery_credential = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()) - .derive_v1_discovery_credential::<CryptoProviderImpl>(); - - let identity_resolution_material = - discovery_credential.unsigned_identity_resolution_material::<CryptoProviderImpl>(); - let verification_material = - discovery_credential.unsigned_verification_material::<CryptoProviderImpl>(); - - match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>( - &mut deserialization_arena!().into_allocator(), - &identity_resolution_material, - &verification_material, - ) { - Ok(section) => { - assert_eq!( - expected_error, - DeserializeError::DataElementParseError( - section.collect_data_elements().unwrap_err() - ) - ); - } - Err(e) => assert_eq!( - expected_error, - DeserializeError::IdentityResolutionOrDeserializationError(e), - ), - }; -}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs index eb2fe01..fc38b1c 100644 --- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs +++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/mod.rs
@@ -14,20 +14,26 @@ use crate::{ credential::v1::*, - deserialization_arena::DeserializationArenaAllocator, extended::{ - deserialize::{ - DecryptedSection, EncryptedIdentityMetadata, EncryptionInfo, SectionContents, - SectionMic, VerificationMode, - }, + deserialize::{DecryptedSection, SectionMic, VerificationMode}, section_signature_payload::*, - METADATA_KEY_LEN, NP_ADV_MAX_SECTION_LEN, + V1IdentityToken, NP_ADV_MAX_SECTION_LEN, V1_IDENTITY_TOKEN_LEN, }, - MetadataKey, V1Header, NP_SVC_UUID, + NP_SVC_UUID, }; +use crate::deserialization_arena::DeserializationArenaAllocator; + #[cfg(any(feature = "devtools", test))] extern crate alloc; + +use crate::{ + extended::{ + deserialize::section::header::CiphertextExtendedIdentityToken, + salt::{MultiSalt, V1Salt}, + }, + header::V1AdvHeader, +}; #[cfg(any(feature = "devtools", test))] use alloc::vec::Vec; #[cfg(feature = "devtools")] @@ -38,24 +44,28 @@ hmac::Hmac, CryptoProvider, }; -use np_hkdf::v1_salt::V1Salt; +use np_hkdf::v1_salt::ExtendedV1Salt; + +#[cfg(test)] +use crate::extended::deserialize::encrypted_section::tests::IdentityResolutionOrDeserializationError; use super::ArenaOutOfSpace; #[cfg(test)] -mod mic_decrypt_tests; -#[cfg(test)] -mod signature_decrypt_tests; +mod tests; /// Represents the contents of an encrypted section /// which are directly employed in identity resolution. /// This does not incorporate any information about credentials. +/// +/// Should be re-used for multiple identity resolution attempts, if applicable, to amortize the +/// cost of calculating this data. #[derive(PartialEq, Eq, Debug)] pub(crate) struct SectionIdentityResolutionContents { - /// The ciphertext for the metadata key - pub(crate) metadata_key_ciphertext: [u8; METADATA_KEY_LEN], - /// The 12-byte cryptographic nonce which is derived from the encryption info - /// and the identity metadata for a particular section. + /// The ciphertext for the identity token + pub(crate) identity_token: CiphertextExtendedIdentityToken, + /// The 12-byte cryptographic nonce which is derived from the salt for a + /// particular section. pub(crate) nonce: AesCtrNonce, } @@ -73,29 +83,34 @@ &self, identity_resolution_material: &SectionIdentityResolutionMaterial, ) -> Option<IdentityMatch<C>> { - let mut decrypt_buf = self.metadata_key_ciphertext; - let aes_key = &identity_resolution_material.aes_key; - let mut cipher = C::AesCtr128::new(aes_key, NonceAndCounter::from_nonce(self.nonce)); + let mut decrypt_buf = self.identity_token.0; + let mut cipher = C::AesCtr128::new( + &identity_resolution_material.aes_key, + NonceAndCounter::from_nonce(self.nonce), + ); cipher.apply_keystream(&mut decrypt_buf[..]); - let metadata_key_hmac_key: np_hkdf::NpHmacSha256Key<C> = - identity_resolution_material.metadata_key_hmac_key.into(); - let expected_metadata_key_hmac = identity_resolution_material.expected_metadata_key_hmac; - metadata_key_hmac_key.verify_hmac(&decrypt_buf[..], expected_metadata_key_hmac).ok().map( - move |_| IdentityMatch { + let identity_token_hmac_key: np_hkdf::NpHmacSha256Key = + identity_resolution_material.identity_token_hmac_key.into(); + identity_token_hmac_key + .verify_hmac::<C>( + &decrypt_buf[..], + identity_resolution_material.expected_identity_token_hmac, + ) + .ok() + .map(move |_| IdentityMatch { cipher, - metadata_key_plaintext: MetadataKey(decrypt_buf), + identity_token: V1IdentityToken(decrypt_buf), nonce: self.nonce, - }, - ) + }) } } /// Carries data about an identity "match" for a particular section /// against some particular V1 identity-resolution crypto-materials. pub(crate) struct IdentityMatch<C: CryptoProvider> { - /// Decrypted metadata key ciphertext - metadata_key_plaintext: MetadataKey, + /// Decrypted identity token + identity_token: V1IdentityToken, /// The AES-Ctr nonce to be used in section decryption and verification nonce: AesCtrNonce, /// The state of the AES-Ctr cipher after successfully decrypting @@ -106,22 +121,24 @@ /// Maximum length of a section's contents, after the metadata-key. #[allow(unused)] -const MAX_SECTION_CONTENTS_LEN: usize = NP_ADV_MAX_SECTION_LEN - METADATA_KEY_LEN; +const MAX_SECTION_CONTENTS_LEN: usize = NP_ADV_MAX_SECTION_LEN - V1_IDENTITY_TOKEN_LEN; /// Bare, decrypted contents from an encrypted section, /// including the decrypted metadata key and the decrypted section ciphertext. /// At this point, verification of the plaintext contents has not yet been performed. -pub(crate) struct RawDecryptedSection<'adv> { - pub(crate) metadata_key_plaintext: MetadataKey, +pub(crate) struct RawDecryptedSection<'a> { + // Only used with feature = "devtools" + #[allow(unused)] + pub(crate) identity_token: V1IdentityToken, pub(crate) nonce: AesCtrNonce, - pub(crate) plaintext_contents: &'adv [u8], + pub(crate) plaintext_contents: &'a [u8], } #[cfg(feature = "devtools")] -impl<'adv> RawDecryptedSection<'adv> { +impl<'a> RawDecryptedSection<'a> { pub(crate) fn to_raw_bytes(&self) -> ArrayView<u8, NP_ADV_MAX_SECTION_LEN> { let mut result = Vec::new(); - result.extend_from_slice(&self.metadata_key_plaintext.0); + result.extend_from_slice(self.identity_token.as_slice()); result.extend_from_slice(self.plaintext_contents); ArrayView::try_from_slice(&result).expect("Won't panic because of the involved lengths") } @@ -130,17 +147,21 @@ /// Represents the contents of an encrypted section, /// independent of the encryption type. #[derive(PartialEq, Eq, Debug)] -pub(crate) struct EncryptedSectionContents<'a> { - pub(crate) section_header: u8, - pub(crate) adv_header: V1Header, - pub(crate) encryption_info: EncryptionInfo, - pub(crate) identity: EncryptedIdentityMetadata, - /// All ciphertext (Contents of identity DE + all DEs) - /// Length must be in `[METADATA_KEY_LEN, NP_ADV_MAX_SECTION_LEN]`. - pub(crate) all_ciphertext: &'a [u8], +pub(crate) struct EncryptedSectionContents<'adv, S> { + adv_header: V1AdvHeader, + format_bytes: &'adv [u8], + pub(crate) salt: S, + /// Ciphertext of identity token (part of section header) + identity_token: CiphertextExtendedIdentityToken, + /// The portion of the ciphertext that has been encrypted. + /// Length must be in `[0, NP_ADV_MAX_SECTION_LEN]`. + section_contents: &'adv [u8], + // The length byte exactly as it appears in the adv. This is the length of the encrypted + // contents plus any additional bytes of suffix + total_section_contents_len: u8, } -impl<'a> EncryptedSectionContents<'a> { +impl<'adv, S: V1Salt> EncryptedSectionContents<'adv, S> { /// Constructs a representation of the contents of an encrypted V1 section /// from the advertisement header, the section header, information about /// the encryption used for identity verification, identity metadata, @@ -148,30 +169,29 @@ /// /// # Panics /// If `all_ciphertext` is greater than `NP_ADV_MAX_SECTION_LEN` bytes, - /// or less than `METADATA_KEY_LEN` bytes. + /// or less than `IDENTITY_TOKEN_LEN` bytes. pub(crate) fn new( - adv_header: V1Header, - section_header: u8, - encryption_info: EncryptionInfo, - identity: EncryptedIdentityMetadata, - all_ciphertext: &'a [u8], + adv_header: V1AdvHeader, + format_bytes: &'adv [u8], + salt: S, + identity_token: CiphertextExtendedIdentityToken, + section_contents_len: u8, + section_contents: &'adv [u8], ) -> Self { - assert!(all_ciphertext.len() >= METADATA_KEY_LEN); - assert!(all_ciphertext.len() <= NP_ADV_MAX_SECTION_LEN); - Self { adv_header, section_header, encryption_info, identity, all_ciphertext } + assert!(section_contents.len() <= NP_ADV_MAX_SECTION_LEN - V1_IDENTITY_TOKEN_LEN); + Self { + adv_header, + format_bytes, + salt, + identity_token, + total_section_contents_len: section_contents_len, + section_contents, + } } /// Gets the salt for this encrypted section - pub(crate) fn salt<C: CryptoProvider>(&self) -> V1Salt<C> { - self.encryption_info.salt().into() - } - - /// Constructs a cryptographic nonce for this encrypted section - /// based on the contained salt. - pub(crate) fn compute_nonce<C: CryptoProvider>(&self) -> AesCtrNonce { - self.salt::<C>() - .derive(Some(self.identity.offset)) - .expect("AES-CTR nonce is a valid HKDF size") + pub(crate) fn salt(&self) -> MultiSalt { + self.salt.into() } /// Constructs some cryptographic contents for section identity-resolution @@ -179,34 +199,30 @@ pub(crate) fn compute_identity_resolution_contents<C: CryptoProvider>( &self, ) -> SectionIdentityResolutionContents { - let nonce = self.compute_nonce::<C>(); - let metadata_key_ciphertext: [u8; METADATA_KEY_LEN] = self.all_ciphertext - [..METADATA_KEY_LEN] - .try_into() - .expect("slice will always fit into same size array"); - - SectionIdentityResolutionContents { nonce, metadata_key_ciphertext } + let nonce = self.salt.compute_nonce::<C>(); + SectionIdentityResolutionContents { nonce, identity_token: self.identity_token } } /// Given an identity-match, decrypts the ciphertext in this encrypted section /// and returns the raw bytes of the decrypted plaintext. pub(crate) fn decrypt_ciphertext<C: CryptoProvider>( &self, - arena: &mut DeserializationArenaAllocator<'a>, + arena: &mut DeserializationArenaAllocator<'adv>, mut identity_match: IdentityMatch<C>, - ) -> Result<RawDecryptedSection<'a>, ArenaOutOfSpace> { - // Fill decrypt_buf with the ciphertext after the metadata key + ) -> Result<RawDecryptedSection<'adv>, ArenaOutOfSpace> { + // Fill decrypt_buf with the ciphertext after the section length let decrypt_buf = - arena.allocate(u8::try_from(self.all_ciphertext.len() - METADATA_KEY_LEN).expect( - "all_ciphertext.len() must be in [METADATA_KEY_LEN, NP_ADV_MAX_SECTION_LEN]", - ))?; - decrypt_buf.copy_from_slice(&self.all_ciphertext[METADATA_KEY_LEN..]); + arena + .allocate(u8::try_from(self.section_contents.len()).expect( + "section_contents.len() must be in [0, NP_ADV_MAX_SECTION_CONTENTS_LEN - EXTENDED_IDENTITY_TOKEN_LEN]", + ))?; + decrypt_buf.copy_from_slice(self.section_contents); // Decrypt everything after the metadata key identity_match.cipher.apply_keystream(decrypt_buf); Ok(RawDecryptedSection { - metadata_key_plaintext: identity_match.metadata_key_plaintext, + identity_token: identity_match.identity_token, nonce: identity_match.nonce, plaintext_contents: decrypt_buf, }) @@ -216,21 +232,21 @@ #[cfg(feature = "devtools")] pub(crate) fn try_resolve_identity_and_decrypt<P: CryptoProvider>( &self, - allocator: &mut DeserializationArenaAllocator<'a>, + allocator: &mut DeserializationArenaAllocator<'adv>, identity_resolution_material: &SectionIdentityResolutionMaterial, ) -> Option<Result<ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, ArenaOutOfSpace>> { - let identity_resolution_contents = self.compute_identity_resolution_contents::<P>(); - identity_resolution_contents.try_match(identity_resolution_material).map(|identity_match| { - let decrypted_section = self.decrypt_ciphertext::<P>(allocator, identity_match)?; - Ok(decrypted_section.to_raw_bytes()) - }) + self.compute_identity_resolution_contents::<P>() + .try_match(identity_resolution_material) + .map(|identity_match| { + Ok(self.decrypt_ciphertext::<P>(allocator, identity_match)?.to_raw_bytes()) + }) } } /// An encrypted section which is verified using a ed25519 signature #[derive(PartialEq, Eq, Debug)] pub(crate) struct SignatureEncryptedSection<'a> { - pub(crate) contents: EncryptedSectionContents<'a>, + pub(crate) contents: EncryptedSectionContents<'a, ExtendedV1Salt>, } impl<'a> SignatureEncryptedSection<'a> { @@ -245,51 +261,41 @@ where P: CryptoProvider, { + let identity_token = identity_match.identity_token; let raw_decrypted = self.contents.decrypt_ciphertext(arena, identity_match)?; - let metadata_key = raw_decrypted.metadata_key_plaintext; let nonce = raw_decrypted.nonce; let remaining = raw_decrypted.plaintext_contents; - if remaining.len() < crypto_provider::ed25519::SIGNATURE_LENGTH { - return Err(SignatureVerificationError::SignatureMissing.into()); - } + let (plaintext_des, sig) = remaining + .split_last_chunk::<{ crypto_provider::ed25519::SIGNATURE_LENGTH }>() + .ok_or(SignatureVerificationError::SignatureMissing)?; - // should not panic due to above check - let (non_identity_des, sig) = - remaining.split_at(remaining.len() - crypto_provider::ed25519::SIGNATURE_LENGTH); + let expected_signature = crypto_provider::ed25519::Signature::from(*sig); - // All implementations only check for 64 bytes, and this will always result in a 64 byte signature. - let expected_signature = - np_ed25519::Signature::<P>::try_from(sig).expect("Signature is always 64 bytes."); - - let section_signature_payload = SectionSignaturePayload::from_deserialized_parts( - self.contents.adv_header.header_byte, - self.contents.section_header, - &self.contents.encryption_info.bytes, + let section_signature_payload = SectionSignaturePayload::new( + self.contents.format_bytes, + self.contents.salt.bytes(), &nonce, - self.contents.identity.header_bytes, - metadata_key, - non_identity_des, + identity_token.as_slice(), + self.contents.total_section_contents_len, + plaintext_des, ); let public_key = verification_material.signature_verification_public_key(); - section_signature_payload.verify(&expected_signature, &public_key).map_err(|e| { - // Length of the payload should fit in the signature verification buffer. - debug_assert!(e != np_ed25519::SignatureVerificationError::PayloadTooBig); - - SignatureVerificationError::SignatureMismatch - })?; - - let salt = self.contents.salt::<P>(); + section_signature_payload.verify::<P::Ed25519>(expected_signature, &public_key).map_err( + |e| { + // Length of the payload should fit in the signature verification buffer. + debug_assert!(e != np_ed25519::SignatureVerificationError::PayloadTooBig); + SignatureVerificationError::SignatureMismatch + }, + )?; Ok(DecryptedSection::new( - self.contents.identity.identity_type, VerificationMode::Signature, - metadata_key, - salt.into(), - // de offset 2 because of leading encryption info and identity DEs - SectionContents::new(self.contents.section_header, non_identity_des, 2), + self.contents.salt(), + identity_token, + plaintext_des, )) } @@ -307,6 +313,13 @@ } /// Try deserializing into a [Section] given some raw signed crypto-material. + /// + /// A less-efficient, one-shot way of getting + /// [EncryptedSectionContents::compute_identity_resolution_contents] and then attempting + /// deserialization. + /// + /// Normally, id resolution contents would be calculated for a bunch of sections, and then have + /// many identities tried on them. This just works for one identity. #[cfg(test)] pub(crate) fn try_resolve_identity_and_deserialize<P: CryptoProvider>( &self, @@ -317,9 +330,9 @@ DecryptedSection, IdentityResolutionOrDeserializationError<SignatureVerificationError>, > { - let section_identity_resolution_contents = - self.contents.compute_identity_resolution_contents::<P>(); - match section_identity_resolution_contents + match self + .contents + .compute_identity_resolution_contents::<P>() .try_match::<P>(identity_resolution_material.as_raw_resolution_material()) { Some(identity_match) => self @@ -330,36 +343,6 @@ } } -/// An error when attempting to resolve an identity and then -/// attempt to deserialize an encrypted advertisement. -/// -/// This should not be exposed publicly, since it's too -/// detailed. -#[cfg(test)] -#[derive(Debug, PartialEq, Eq)] -pub(crate) enum IdentityResolutionOrDeserializationError<V: VerificationError> { - /// Failed to match the encrypted adv to an identity - IdentityMatchingError, - /// Failed to deserialize the encrypted adv after matching the identity - DeserializationError(DeserializationError<V>), -} - -#[cfg(test)] -impl<V: VerificationError> From<DeserializationError<V>> - for IdentityResolutionOrDeserializationError<V> -{ - fn from(deserialization_error: DeserializationError<V>) -> Self { - Self::DeserializationError(deserialization_error) - } -} - -#[cfg(test)] -impl<V: VerificationError> From<V> for IdentityResolutionOrDeserializationError<V> { - fn from(verification_error: V) -> Self { - Self::DeserializationError(DeserializationError::VerificationError(verification_error)) - } -} - /// An error when attempting to deserialize an encrypted advertisement, /// assuming that we already have an identity-match. /// @@ -406,7 +389,7 @@ /// An encrypted section whose contents are verified to match a message integrity code (MIC) #[derive(PartialEq, Eq, Debug)] pub(crate) struct MicEncryptedSection<'a> { - pub(crate) contents: EncryptedSectionContents<'a>, + pub(crate) contents: EncryptedSectionContents<'a, MultiSalt>, pub(crate) mic: SectionMic, } @@ -418,48 +401,71 @@ &self, allocator: &mut DeserializationArenaAllocator<'a>, identity_match: IdentityMatch<P>, - verification_material: &UnsignedSectionVerificationMaterial, + crypto_material: &impl V1DiscoveryCryptoMaterial, ) -> Result<DecryptedSection<'a>, DeserializationError<MicVerificationError>> where P: CryptoProvider, { - let raw_decrypted = self.contents.decrypt_ciphertext(allocator, identity_match)?; - let metadata_key = raw_decrypted.metadata_key_plaintext; - let nonce = raw_decrypted.nonce; - let remaining_des = raw_decrypted.plaintext_contents; + let hmac_key = match self.contents.salt { + MultiSalt::Short(_) => { + crypto_material.mic_short_salt_verification_material::<P>().mic_hmac_key() + } + MultiSalt::Extended(_) => { + crypto_material.mic_extended_salt_verification_material::<P>().mic_hmac_key() + } + }; + let mut mic_hmac = hmac_key.build_hmac::<P>(); // if mic is ok, the section was generated by someone holding at least the shared credential - let mut mic_hmac = verification_material.mic_hmac_key::<P>().build_hmac(); mic_hmac.update(&NP_SVC_UUID); - mic_hmac.update(&[self.contents.adv_header.header_byte]); - mic_hmac.update(&[self.contents.section_header]); - mic_hmac.update(&self.contents.encryption_info.bytes); - mic_hmac.update(&nonce); - mic_hmac.update(&self.contents.identity.header_bytes); - mic_hmac.update(self.contents.all_ciphertext); + mic_hmac.update(&[self.contents.adv_header.contents()]); + // section format + mic_hmac.update(self.contents.format_bytes); + // salt bytes + mic_hmac.update(self.contents.salt.as_slice()); + // nonce + mic_hmac.update(identity_match.nonce.as_slice()); + // ciphertext identity token + mic_hmac.update(self.contents.identity_token.0.as_slice()); + // section payload len + mic_hmac.update(&[self.contents.total_section_contents_len]); + // rest of encrypted contents + mic_hmac.update(self.contents.section_contents); mic_hmac // adv only contains first 16 bytes of HMAC .verify_truncated_left(&self.mic.mic) .map_err(|_e| MicVerificationError::MicMismatch)?; - let salt = self.contents.salt::<P>(); - + // plaintext identity token, already decrypted during identity match + let identity_token = identity_match.identity_token; + let raw_decrypted = self.contents.decrypt_ciphertext(allocator, identity_match)?; Ok(DecryptedSection::new( - self.contents.identity.identity_type, VerificationMode::Mic, - metadata_key, - salt.into(), - // offset 2 for encryption info and identity DEs - SectionContents::new(self.contents.section_header, remaining_des, 2), + self.contents.salt(), + identity_token, + raw_decrypted.plaintext_contents, )) } /// Try decrypting into some raw bytes given some raw unsigned crypto-material. #[cfg(feature = "devtools")] - pub(crate) fn try_resolve_identity_and_decrypt<P: CryptoProvider>( + pub(crate) fn try_resolve_short_salt_identity_and_decrypt<P: CryptoProvider>( &self, allocator: &mut DeserializationArenaAllocator<'a>, - identity_resolution_material: &UnsignedSectionIdentityResolutionMaterial, + identity_resolution_material: &MicShortSaltSectionIdentityResolutionMaterial, + ) -> Option<Result<ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, ArenaOutOfSpace>> { + self.contents.try_resolve_identity_and_decrypt::<P>( + allocator, + identity_resolution_material.as_raw_resolution_material(), + ) + } + + /// Try decrypting into some raw bytes given some raw unsigned crypto-material. + #[cfg(feature = "devtools")] + pub(crate) fn try_resolve_extended_salt_identity_and_decrypt<P: CryptoProvider>( + &self, + allocator: &mut DeserializationArenaAllocator<'a>, + identity_resolution_material: &MicExtendedSaltSectionIdentityResolutionMaterial, ) -> Option<Result<ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, ArenaOutOfSpace>> { self.contents.try_resolve_identity_and_decrypt::<P>( allocator, @@ -472,20 +478,27 @@ pub(crate) fn try_resolve_identity_and_deserialize<P: CryptoProvider>( &self, allocator: &mut DeserializationArenaAllocator<'a>, - identity_resolution_material: &UnsignedSectionIdentityResolutionMaterial, - verification_material: &UnsignedSectionVerificationMaterial, + crypto_material: &impl V1DiscoveryCryptoMaterial, ) -> Result<DecryptedSection, IdentityResolutionOrDeserializationError<MicVerificationError>> { let section_identity_resolution_contents = self.contents.compute_identity_resolution_contents::<P>(); - match section_identity_resolution_contents - .try_match::<P>(identity_resolution_material.as_raw_resolution_material()) - { - Some(identity_match) => self - .try_deserialize(allocator, identity_match, verification_material) - .map_err(|e| e.into()), - None => Err(IdentityResolutionOrDeserializationError::IdentityMatchingError), + + let identity_match = match self.contents.salt { + MultiSalt::Short(_) => section_identity_resolution_contents.try_match::<P>( + crypto_material + .mic_short_salt_identity_resolution_material::<P>() + .as_raw_resolution_material(), + ), + MultiSalt::Extended(_) => section_identity_resolution_contents.try_match::<P>( + crypto_material + .mic_extended_salt_identity_resolution_material::<P>() + .as_raw_resolution_material(), + ), } + .ok_or(IdentityResolutionOrDeserializationError::IdentityMatchingError)?; + + self.try_deserialize(allocator, identity_match, crypto_material).map_err(|e| e.into()) } }
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs deleted file mode 100644 index 7801744..0000000 --- a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/signature_decrypt_tests.rs +++ /dev/null
@@ -1,570 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use crate::deserialization_arena; -use crate::extended::data_elements::TxPowerDataElement; -use crate::extended::deserialize::{ - DataElementParseError, DecryptedSection, EncryptionInfo, RawV1Salt, SectionContents, -}; -use crate::extended::serialize::{AdvertisementType, DeSalt}; -use crate::shared_data::TxPower; -use crate::{ - credential::v1::*, - de_type::EncryptedIdentityDataElementType, - extended::{ - deserialize::{ - encrypted_section::{ - EncryptedSectionContents, IdentityResolutionOrDeserializationError, - SignatureEncryptedSection, SignatureVerificationError, - }, - parse_sections, - test_stubs::IntermediateSectionExt, - CiphertextSection, DataElement, EncryptedIdentityMetadata, VerificationMode, - }, - section_signature_payload::*, - serialize::{ - AdvBuilder, CapacityLimitedVec, SignedEncryptedSectionEncoder, SingleTypeDataElement, - WriteDataElement, - }, - NP_ADV_MAX_SECTION_LEN, - }, - parse_adv_header, AdvHeader, MetadataKey, Section, -}; -use crypto_provider::{aes::ctr::AesCtrNonce, CryptoProvider}; -use crypto_provider_default::CryptoProviderImpl; -use np_hkdf::v1_salt; -use np_hkdf::v1_salt::V1Salt; -use sink::Sink; -use std::{prelude::rust_2021::*, vec}; - -type KeyPair = np_ed25519::KeyPair<CryptoProviderImpl>; - -#[test] -fn deserialize_signature_encrypted_correct_keys() { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let raw_salt = RawV1Salt([3; 16]); - let section_salt = V1Salt::<CryptoProviderImpl>::from(raw_salt); - let identity_type = EncryptedIdentityDataElementType::Private; - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let key_pair = KeyPair::generate(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); - - let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - raw_salt, - &broadcast_cm, - )) - .unwrap(); - - let txpower_de = TxPowerDataElement::from(TxPower::try_from(7).unwrap()); - section_builder.add_de(|_| txpower_de.clone()).unwrap(); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let adv_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(adv_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - let contents = if let CiphertextSection::SignatureEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - let mut encryption_info_bytes = [0_u8; 19]; - encryption_info_bytes[0..2].copy_from_slice(&[0x91, 0x10]); - encryption_info_bytes[2] = 0x08; - encryption_info_bytes[3..].copy_from_slice(section_salt.as_slice()); - - let section_len = 19 + 2 + 16 + 2 + 64; - assert_eq!( - &SignatureEncryptedSection { - contents: EncryptedSectionContents { - section_header: section_len, - adv_header, - encryption_info: EncryptionInfo { bytes: encryption_info_bytes }, - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x1], - offset: 1.into(), - identity_type: EncryptedIdentityDataElementType::Private, - }, - // adv header + salt + section header + encryption info + identity header - all_ciphertext: &adv.as_slice()[1 + 1 + 19 + 2..], - }, - }, - contents - ); - - // plaintext is correct - { - let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>( - key_seed, - key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_pair.public().to_bytes(), - ) - .expect("public key bytes are valid since they are generated from a key pair"); - let signed_identity_resolution_material = - crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>(); - let identity_resolution_contents = - contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>(); - let identity_match = identity_resolution_contents - .try_match::<CryptoProviderImpl>( - &signed_identity_resolution_material.into_raw_resolution_material(), - ) - .unwrap(); - - let arena = deserialization_arena!(); - let mut allocator = arena.into_allocator(); - let decrypted = - contents.contents.decrypt_ciphertext(&mut allocator, identity_match).unwrap(); - - let mut expected = Vec::new(); - expected.extend_from_slice(txpower_de.de_header().serialize().as_slice()); - let _ = txpower_de.write_de_contents(&mut expected); - - let nonce: AesCtrNonce = section_salt.derive(Some(1.into())).unwrap(); - - let mut encryption_info = vec![0x91, 0x10, 0x08]; - encryption_info.extend_from_slice(section_salt.as_slice()); - let encryption_info: [u8; EncryptionInfo::TOTAL_DE_LEN] = - encryption_info.try_into().unwrap(); - - let sig_payload = SectionSignaturePayload::from_deserialized_parts( - 0x20, - section_len, - &encryption_info, - &nonce, - [0x90, 0x1], - metadata_key, - &expected, - ); - - expected.extend_from_slice(&sig_payload.sign(&key_pair).to_bytes()); - assert_eq!(metadata_key, decrypted.metadata_key_plaintext); - assert_eq!(nonce, decrypted.nonce); - assert_eq!(&expected, decrypted.plaintext_contents); - } - - // deserialization to Section works - { - let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>( - key_seed, - key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_pair.public().to_bytes(), - ) - .expect("public key bytes are valid since they are generated from a key pair"); - let signed_identity_resolution_material = - crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>(); - let signed_verification_material = - crypto_material.signed_verification_material::<CryptoProviderImpl>(); - - let arena = deserialization_arena!(); - let mut allocator = arena.into_allocator(); - let section = contents - .try_resolve_identity_and_deserialize::<CryptoProviderImpl>( - &mut allocator, - &signed_identity_resolution_material, - &signed_verification_material, - ) - .unwrap(); - - assert_eq!( - DecryptedSection::new( - EncryptedIdentityDataElementType::Private, - VerificationMode::Signature, - metadata_key, - raw_salt, - SectionContents { - section_header: 19 + 2 + 16 + 1 + 1 + 64, - data_element_start_offset: 2, - de_region_excl_identity: - &[txpower_de.de_header().serialize().as_slice(), &[7],].concat(), - }, - ), - section - ); - let data_elements = section.collect_data_elements().unwrap(); - assert_eq!( - data_elements, - &[DataElement { offset: 2.into(), de_type: 0x05_u8.into(), contents: &[7] }] - ); - - assert_eq!( - vec![(v1_salt::DataElementOffset::from(2_u8), TxPowerDataElement::DE_TYPE, vec![7u8])], - data_elements - .into_iter() - .map(|de| (de.offset(), de.de_type(), de.contents().to_vec())) - .collect::<Vec<_>>() - ); - } -} - -#[test] -fn deserialize_signature_encrypted_incorrect_aes_key_error() { - // bad aes key -> bad metadata key plaintext - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - Some([0xFF; 16].into()), - None, - None, - None, - ); -} - -#[test] -fn deserialize_signature_encrypted_incorrect_metadata_key_hmac_key_error() { - // bad metadata key hmac key -> bad calculated metadata key mac - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - None, - Some([0xFF; 32].into()), - None, - None, - ); -} - -#[test] -fn deserialize_signature_encrypted_incorrect_expected_metadata_key_hmac_error() { - // bad expected metadata key mac - do_bad_deserialize_params::<CryptoProviderImpl>( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - None, - None, - Some([0xFF; 32]), - None, - ); -} - -#[test] -fn deserialize_signature_encrypted_incorrect_pub_key_error() { - // a random pub key will lead to signature mismatch - do_bad_deserialize_params::<CryptoProviderImpl>( - SignatureVerificationError::SignatureMismatch.into(), - None, - None, - None, - Some(KeyPair::generate().public()), - ); -} - -#[test] -fn deserialize_signature_encrypted_incorrect_salt_error() { - // bad salt -> bad iv -> bad metadata key plaintext - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - IdentityResolutionOrDeserializationError::IdentityMatchingError, - ), - None, - |_| {}, - |adv_mut| adv_mut[5..21].copy_from_slice(&[0xFF; 16]), - ) -} - -#[test] -fn deserialize_signature_encrypted_tampered_signature_error() { - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - SignatureVerificationError::SignatureMismatch.into(), - ), - None, - |_| {}, - // flip a bit in the middle of the signature - |adv_mut| { - let len = adv_mut.len(); - adv_mut[len - 30] ^= 0x1 - }, - ) -} - -#[test] -fn deserialize_signature_encrypted_tampered_ciphertext_error() { - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - SignatureVerificationError::SignatureMismatch.into(), - ), - None, - |_| {}, - // flip a bit outside of the signature - |adv_mut| { - let len = adv_mut.len(); - adv_mut[len - 1 - 64] ^= 0x1 - }, - ) -} - -#[test] -fn deserialize_signature_encrypted_missing_signature_de_error() { - let section_len = 19 + 2 + 16 + 1 + 1; - do_bad_deserialize_tampered( - DeserializeError::IdentityResolutionOrDeserializationError( - SignatureVerificationError::SignatureMissing.into(), - ), - Some(section_len), - |_| {}, - |adv_mut| { - // chop off signature DE - adv_mut.truncate(adv_mut.len() - 64); - // fix section length - adv_mut[1] = section_len; - }, - ) -} - -#[test] -fn deserialize_signature_encrypted_des_wont_parse() { - do_bad_deserialize_tampered( - DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd), - Some(19 + 2 + 16 + 1 + 1 + 64 + 1), - // add an impossible DE - |section| section.try_push(0xFF).unwrap(), - |_| {}, - ) -} - -/// Attempt a deserialization that will fail when using the provided parameters for decryption only. -/// `None` means use the correct value for that parameter. -fn do_bad_deserialize_params<C: CryptoProvider>( - error: IdentityResolutionOrDeserializationError<SignatureVerificationError>, - aes_key: Option<crypto_provider::aes::Aes128Key>, - metadata_key_hmac_key: Option<np_hkdf::NpHmacSha256Key<C>>, - expected_metadata_key_hmac: Option<[u8; 32]>, - pub_key: Option<np_ed25519::PublicKey<C>>, -) { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let section_salt: v1_salt::V1Salt<C> = [3; 16].into(); - let identity_type = EncryptedIdentityDataElementType::Private; - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::new(&key_seed); - let key_pair = np_ed25519::KeyPair::<C>::generate(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); - - let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::new( - identity_type, - section_salt.into(), - &broadcast_cm, - )) - .unwrap(); - - section_builder - .add_de_res(|_: DeSalt<C>| TxPower::try_from(2).map(TxPowerDataElement::from)) - .unwrap(); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - let contents = if let CiphertextSection::SignatureEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - let signed_identity_resolution_material = - SignedSectionIdentityResolutionMaterial::from_raw(SectionIdentityResolutionMaterial { - aes_key: aes_key.unwrap_or_else(|| key_seed_hkdf.extended_signed_section_aes_key()), - - metadata_key_hmac_key: *metadata_key_hmac_key - .unwrap_or_else(|| key_seed_hkdf.extended_signed_metadata_key_hmac_key()) - .as_bytes(), - expected_metadata_key_hmac: expected_metadata_key_hmac.unwrap_or_else(|| { - key_seed_hkdf - .extended_signed_metadata_key_hmac_key() - .calculate_hmac(&metadata_key.0) - }), - }); - - let signed_verification_material = SignedSectionVerificationMaterial { - validated_public_key: ValidatedPublicKey::from_raw_bytes::<CryptoProviderImpl>( - pub_key.unwrap_or_else(|| key_pair.public()).to_bytes(), - ) - .expect("public key should be valid bytes"), - }; - - assert_eq!( - error, - contents - .try_resolve_identity_and_deserialize::<C>( - &mut deserialization_arena!().into_allocator(), - &signed_identity_resolution_material, - &signed_verification_material, - ) - .unwrap_err() - ); -} - -#[derive(Debug, PartialEq)] -enum DeserializeError { - IdentityResolutionOrDeserializationError( - IdentityResolutionOrDeserializationError<SignatureVerificationError>, - ), - DataElementParseError(DataElementParseError), -} - -/// Run a test that mangles the advertisement contents before attempting to deserialize. -/// -/// Since the advertisement is ciphertext, only changes outside -fn do_bad_deserialize_tampered( - expected_error: DeserializeError, - expected_section_len: Option<u8>, - mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), - mangle_adv_contents: impl Fn(&mut Vec<u8>), -) { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let section_salt: v1_salt::V1Salt<CryptoProviderImpl> = [3; 16].into(); - let identity_type = EncryptedIdentityDataElementType::Private; - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let key_pair = KeyPair::generate(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); - - let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::new( - identity_type, - section_salt.into(), - &broadcast_cm, - )) - .unwrap(); - - section_builder - .add_de_res(|_: DeSalt<CryptoProviderImpl>| { - TxPower::try_from(2).map(TxPowerDataElement::from) - }) - .unwrap(); - - mangle_section(&mut section_builder.section); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - let mut adv_mut = adv.as_slice().to_vec(); - mangle_adv_contents(&mut adv_mut); - - let (remaining, header) = parse_adv_header(&adv_mut).unwrap(); - - let adv_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(adv_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections.into_iter().next().unwrap(); - let enc_section = section.as_ciphertext().unwrap(); - let contents = if let CiphertextSection::SignatureEncryptedIdentity(contents) = &enc_section { - contents - } else { - panic!("incorrect flavor"); - }; - - let mut encryption_info_bytes = [0_u8; 19]; - encryption_info_bytes[0..2].copy_from_slice(&[0x91, 0x10]); - encryption_info_bytes[2] = 0x08; - encryption_info_bytes[3..].copy_from_slice(&adv_mut[5..21]); - - let section_len = 19 + 2 + 16 + 2 + 64; - assert_eq!( - &SignatureEncryptedSection { - contents: EncryptedSectionContents { - section_header: expected_section_len.unwrap_or(section_len), - adv_header, - encryption_info: EncryptionInfo { bytes: encryption_info_bytes }, - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x1], - offset: 1.into(), - identity_type: EncryptedIdentityDataElementType::Private, - }, - all_ciphertext: &adv_mut[1 + 1 + 19 + 2..], - }, - }, - contents - ); - - let crypto_material = V1DiscoveryCredential::new::<CryptoProviderImpl>( - key_seed, - key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_seed_hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_pair.public().to_bytes(), - ) - .expect("public key bytes are valid since they are generated from a key pair"); - let identity_resolution_material = - crypto_material.signed_identity_resolution_material::<CryptoProviderImpl>(); - let verification_material = - crypto_material.signed_verification_material::<CryptoProviderImpl>(); - - match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>( - &mut deserialization_arena!().into_allocator(), - &identity_resolution_material, - &verification_material, - ) { - Ok(section) => { - assert_eq!( - expected_error, - DeserializeError::DataElementParseError( - section.collect_data_elements().unwrap_err() - ), - ); - } - Err(e) => assert_eq!( - expected_error, - DeserializeError::IdentityResolutionOrDeserializationError(e), - ), - }; -}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests.rs new file mode 100644 index 0000000..2afa41c --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests.rs
@@ -0,0 +1,88 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +use super::*; +use crate::extended::V1_IDENTITY_TOKEN_LEN; +use np_hkdf::v1_salt::{ExtendedV1Salt, EXTENDED_SALT_LEN}; + +#[cfg(test)] +mod mic_decrypt_tests; + +#[cfg(test)] +mod signature_decrypt_tests; + +#[cfg(test)] +mod coverage_gaming; + +/// An error when attempting to resolve an identity and then +/// attempt to deserialize an encrypted advertisement. +/// +/// This should not be exposed publicly, since it's too +/// detailed. +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum IdentityResolutionOrDeserializationError<V: VerificationError> { + /// Failed to match the encrypted adv to an identity + IdentityMatchingError, + /// Failed to deserialize the encrypted adv after matching the identity + DeserializationError(DeserializationError<V>), +} + +impl<V: VerificationError> From<DeserializationError<V>> + for IdentityResolutionOrDeserializationError<V> +{ + fn from(deserialization_error: DeserializationError<V>) -> Self { + Self::DeserializationError(deserialization_error) + } +} + +impl<V: VerificationError> From<V> for IdentityResolutionOrDeserializationError<V> { + fn from(verification_error: V) -> Self { + Self::DeserializationError(DeserializationError::VerificationError(verification_error)) + } +} + +pub(crate) fn first_section_contents(after_version_header: &[u8]) -> &[u8] { + &after_version_header[1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1..] +} + +pub(crate) fn first_section_identity_token( + salt: MultiSalt, + after_version_header: &[u8], +) -> CiphertextExtendedIdentityToken { + // Next 16 bytes after 1 byte format and 16 byte salt + after_version_header[1 + salt.as_slice().len()..][..V1_IDENTITY_TOKEN_LEN] + .try_into() + .map(|arr: [u8; V1_IDENTITY_TOKEN_LEN]| arr.into()) + .unwrap() +} + +pub(crate) fn first_section_format(after_version_header: &[u8]) -> &[u8] { + // 1 byte of format comes at the beginning + &after_version_header[..1] +} + +pub(crate) fn first_section_salt(after_version_header: &[u8]) -> ExtendedV1Salt { + // Next 16 bytes after 1 byte format + after_version_header[1..][..EXTENDED_SALT_LEN] + .try_into() + .map(|arr: [u8; EXTENDED_SALT_LEN]| arr.into()) + .unwrap() +} + +pub(crate) fn first_section_contents_len(after_version_header: &[u8]) -> u8 { + // section len is the first byte after format + salt + identity token + after_version_header[1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN..][0] +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/coverage_gaming.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/coverage_gaming.rs new file mode 100644 index 0000000..0d8ba8f --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/coverage_gaming.rs
@@ -0,0 +1,60 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +use super::super::*; +use alloc::format; +use crypto_provider_default::CryptoProviderImpl; + +#[test] +fn section_identity_resolution_content_derives() { + let salt: ExtendedV1Salt = [0; 16].into(); + let nonce = salt.compute_nonce::<CryptoProviderImpl>(); + let token = CiphertextExtendedIdentityToken([0; 16]); + let section = SectionIdentityResolutionContents { identity_token: token, nonce }; + assert_eq!(section, section); + let _ = format!("{:?}", section); +} + +#[test] +fn sig_encrypted_section_debug() { + let ss = SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + V1AdvHeader::new(0), + &[0], + [0x00; 16].into(), + [0x00; V1_IDENTITY_TOKEN_LEN].into(), + 1, + &[0x00; 1], + ), + }; + let _ = format!("{:?}", ss); +} + +#[test] +fn error_enum_debug_derives() { + let mic_err = MicVerificationError::MicMismatch; + let _ = format!("{:?}", mic_err); + + let sig_err = SignatureVerificationError::SignatureMissing; + let _ = format!("{:?}", sig_err); + + let deser_err = DeserializationError::ArenaOutOfSpace::<MicVerificationError>; + let _ = format!("{:?}", deser_err); + + let err = + IdentityResolutionOrDeserializationError::IdentityMatchingError::<MicVerificationError>; + let _ = format!("{:?}", err); +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/mic_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/mic_decrypt_tests.rs new file mode 100644 index 0000000..5d2f759 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/mic_decrypt_tests.rs
@@ -0,0 +1,642 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use super::super::*; +use crate::{ + deserialization_arena, + extended::{ + data_elements::TxPowerDataElement, + deserialize::{ + encrypted_section::tests::first_section_identity_token, + section::intermediate::{ + parse_sections, tests::IntermediateSectionExt, CiphertextSection, + }, + DataElement, DataElementParseError, Section, + }, + salt::{ShortV1Salt, SHORT_SALT_LEN}, + serialize::{ + AdvBuilder, AdvertisementType, CapacityLimitedVec, MicEncryptedSectionEncoder, + WriteDataElement, + }, + V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN, + }, + shared_data::TxPower, + NpVersionHeader, +}; +use crypto_provider::ed25519; +use crypto_provider_default::CryptoProviderImpl; +use np_hkdf::{v1_salt::EXTENDED_SALT_LEN, DerivedSectionKeys}; +use sink::Sink; + +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; + +#[test] +fn deserialize_mic_encrypted_correct_keys_extended_salt() { + deserialize_mic_encrypted_correct_keys(ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into()) +} + +#[test] +fn deserialize_mic_encrypted_correct_keys_short_salt() { + deserialize_mic_encrypted_correct_keys(ShortV1Salt::from([3; SHORT_SALT_LEN]).into()) +} + +fn deserialize_mic_encrypted_correct_keys(salt: MultiSalt) { + let identity_token = V1IdentityToken::from([1; 16]); + let key_seed = [2; 32]; + let broadcast_cm = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let mut section_builder = adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + salt, + &broadcast_cm, + )) + .unwrap(); + + let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap()); + section_builder.add_de(|_| txpower_de.clone()).unwrap(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + let adv = adv_builder.into_advertisement(); + + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let adv_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(adv_header, remaining).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + + let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + // deserializing to Section works + let discovery_credential = V1BroadcastCredential::new(key_seed, identity_token, private_key) + .derive_discovery_credential::<CryptoProviderImpl>(); + + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let section = contents + .try_resolve_identity_and_deserialize::<CryptoProviderImpl>( + &mut allocator, + &discovery_credential, + ) + .unwrap(); + + assert_eq!( + DecryptedSection::new( + VerificationMode::Mic, + salt, + identity_token, + &[txpower_de.de_header().serialize().as_slice(), &[5],].concat(), + ), + section + ); + let data_elements = section.collect_data_elements().unwrap(); + assert_eq!(data_elements, &[DataElement::new(0.into(), 0x05_u8.into(), &[5])]); + + let (_header, contents_bytes) = + remaining.split_at(1 + 1 + salt.as_slice().len() + V1_IDENTITY_TOKEN_LEN); + assert_eq!( + &MicEncryptedSection { + contents: EncryptedSectionContents { + adv_header, + format_bytes: &[match salt { + MultiSalt::Short(_) => { + V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN + } + MultiSalt::Extended(_) => { + V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN + } + }], + salt, + identity_token: first_section_identity_token(salt, remaining), + section_contents: &contents_bytes + [..contents_bytes.len() - SectionMic::CONTENTS_LEN], + total_section_contents_len: contents_bytes.len().try_into().unwrap(), + }, + mic: SectionMic { + mic: contents_bytes[contents_bytes.len() - SectionMic::CONTENTS_LEN..] + .try_into() + .unwrap() + }, + }, + contents + ); + + // plaintext is correct + { + let identity_resolution_contents = + contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>(); + let identity_match = identity_resolution_contents + .try_match::<CryptoProviderImpl>(&match salt { + MultiSalt::Short(_) => discovery_credential + .mic_short_salt_identity_resolution_material::<CryptoProviderImpl>() + .into_raw_resolution_material(), + MultiSalt::Extended(_) => discovery_credential + .mic_extended_salt_identity_resolution_material::<CryptoProviderImpl>() + .into_raw_resolution_material(), + }) + .unwrap(); + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let decrypted = contents + .contents + .decrypt_ciphertext::<CryptoProviderImpl>(&mut allocator, identity_match) + .unwrap(); + + let mut expected = Vec::new(); + // battery de + expected.extend_from_slice(txpower_de.clone().de_header().serialize().as_slice()); + let _ = txpower_de.write_de_contents(&mut expected); + + assert_eq!(identity_token, decrypted.identity_token); + assert_eq!(&expected, decrypted.plaintext_contents); + } +} + +#[test] +fn deserialize_mic_encrypted_short_salt_incorrect_aes_key_error() { + // bad aes key -> bad metadata key plaintext + do_bad_deserialize_params::<CryptoProviderImpl>( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_short_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .aes_key = [0xFF; 16].into(); + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_incorrect_identity_token_hmac_key_error() { + // bad metadata key hmac key -> bad calculated metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_short_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .identity_token_hmac_key = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_incorrect_mic_hmac_key_error() { + // bad mic hmac key -> bad calculated mic + do_bad_deserialize_params::<CryptoProviderImpl>( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + MicVerificationError::MicMismatch.into(), + |cm| { + cm.mic_short_salt_verification_material.mic_hmac_key = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_incorrect_expected_identity_token_hmac_error() { + // bad expected metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_short_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .expected_identity_token_hmac = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_incorrect_aes_key_error() { + // bad aes key -> bad metadata key plaintext + do_bad_deserialize_params::<CryptoProviderImpl>( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_extended_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .aes_key = [0xFF; 16].into(); + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_incorrect_identity_token_hmac_key_error() { + // bad metadata key hmac key -> bad calculated metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_extended_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .identity_token_hmac_key = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_incorrect_mic_hmac_key_error() { + // bad mic hmac key -> bad calculated mic + do_bad_deserialize_params::<CryptoProviderImpl>( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + MicVerificationError::MicMismatch.into(), + |cm| { + cm.mic_extended_salt_verification_material.mic_hmac_key = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_incorrect_expected_identity_token_hmac_error() { + // bad expected metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + IdentityResolutionOrDeserializationError::IdentityMatchingError, + |cm| { + cm.mic_extended_salt_identity_resolution_material + .as_mut_raw_resolution_material() + .expected_identity_token_hmac = [0xFF; 32]; + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_incorrect_salt_error() { + // bad salt -> bad iv -> bad metadata key plaintext + do_bad_deserialize_tampered( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + ), + |_| {}, + // replace the extended salt bytes + |adv| adv[2..18].fill(0xFF), + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_de_that_wont_parse() { + // add an extra byte to the section, leading it to try to parse a DE that doesn't exist + do_bad_deserialize_tampered( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd), + |sec| sec.try_push(0xFF).unwrap(), + |_| {}, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_tampered_mic_error() { + // flip a bit in the first MIC byte + do_bad_deserialize_tampered( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + MicVerificationError::MicMismatch.into(), + ), + |_| {}, + |adv| { + let mic_start = adv.len() - 16; + adv[mic_start] ^= 0x01 + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_extended_salt_tampered_payload_error() { + // flip the last payload bit + do_bad_deserialize_tampered( + ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + MicVerificationError::MicMismatch.into(), + ), + |_| {}, + |adv| { + let before_mic = adv.len() - 17; + adv[before_mic] ^= 0x01 + }, + ); +} +#[test] +fn deserialize_mic_encrypted_short_salt_incorrect_salt_error() { + // bad salt -> bad iv -> bad metadata key plaintext + do_bad_deserialize_tampered( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + ), + |_| {}, + // replace the extended salt bytes + |adv| adv[2..4].fill(0xFF), + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_de_that_wont_parse() { + // add an extra byte to the section, leading it to try to parse a DE that doesn't exist + do_bad_deserialize_tampered( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd), + |sec| sec.try_push(0xFF).unwrap(), + |_| {}, + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_tampered_mic_error() { + // flip a bit in the first MIC byte + do_bad_deserialize_tampered( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + MicVerificationError::MicMismatch.into(), + ), + |_| {}, + |adv| { + let mic_start = adv.len() - 16; + adv[mic_start] ^= 0x01 + }, + ); +} + +#[test] +fn deserialize_mic_encrypted_short_salt_tampered_payload_error() { + // flip the last payload bit + do_bad_deserialize_tampered( + ShortV1Salt::from([3; SHORT_SALT_LEN]).into(), + DeserializeError::IdentityResolutionOrDeserializationError( + MicVerificationError::MicMismatch.into(), + ), + |_| {}, + |adv| { + let before_mic = adv.len() - 17; + adv[before_mic] ^= 0x01 + }, + ); +} + +#[test] +fn arena_out_of_space_on_mic_verify() { + let identity_token = V1IdentityToken::from([1; 16]); + let key_seed = [2; 32]; + let section_salt = ExtendedV1Salt::from([3; 16]); + let broadcast_cm = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let mut section_builder = adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cm, + )) + .unwrap(); + + let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap()); + section_builder.add_de(|_| txpower_de.clone()).unwrap(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + let adv = adv_builder.into_advertisement(); + + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let adv_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(adv_header, remaining).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + + let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + // deserializing to Section works + let discovery_credential = V1BroadcastCredential::new(key_seed, identity_token, private_key) + .derive_discovery_credential::<CryptoProviderImpl>(); + + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let _ = allocator.allocate(250).unwrap(); + let res = contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>( + &mut allocator, + &discovery_credential, + ); + assert_eq!( + Err(IdentityResolutionOrDeserializationError::DeserializationError( + DeserializationError::ArenaOutOfSpace + )), + res + ); +} + +/// Attempt a decryption that will fail when using the provided parameters for decryption only. +/// `None` means use the correct value for that parameter. +fn do_bad_deserialize_params<C: CryptoProvider>( + salt: MultiSalt, + error: IdentityResolutionOrDeserializationError<MicVerificationError>, + mut mangle_crypto_material: impl FnMut(&mut PrecalculatedV1DiscoveryCryptoMaterial), +) { + let identity_token = V1IdentityToken([1; 16]); + let key_seed = [2; 32]; + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); + + let mut section_builder = adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + salt, + &broadcast_cm, + )) + .unwrap(); + + section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap(); + + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let adv = adv_builder.into_advertisement(); + + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(v1_header, remaining).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + // start with correct crypto material + let mut crypto_material = V1DiscoveryCredential::new( + key_seed, + key_seed_hkdf + .v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(&identity_token.0), + key_seed_hkdf + .v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(&identity_token.0), + key_seed_hkdf + .v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<C>(&identity_token.0), + crypto_provider::ed25519::PrivateKey::generate::<C::Ed25519>() + .derive_public_key::<C::Ed25519>(), + ) + .to_precalculated::<C>(); + + // then break it per the test case + mangle_crypto_material(&mut crypto_material); + + assert_eq!( + error, + contents + .try_resolve_identity_and_deserialize::<C>( + &mut deserialization_arena!().into_allocator(), + &crypto_material + ) + .unwrap_err() + ); +} + +#[derive(Debug, PartialEq)] +enum DeserializeError { + IdentityResolutionOrDeserializationError( + IdentityResolutionOrDeserializationError<MicVerificationError>, + ), + DataElementParseError(DataElementParseError), +} + +fn do_bad_deserialize_tampered( + salt: MultiSalt, + expected_error: DeserializeError, + mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), + mangle_adv: impl Fn(&mut Vec<u8>), +) { + let metadata_key = V1IdentityToken([1; 16]); + let key_seed = [2; 32]; + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = V1BroadcastCredential::new( + key_seed, + metadata_key, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); + + let mut section_builder = adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + salt, + &broadcast_cm, + )) + .unwrap(); + + section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap(); + + mangle_section(&mut section_builder.section); + + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let adv = adv_builder.into_advertisement(); + let mut adv_mut = adv.as_slice().to_vec(); + mangle_adv(&mut adv_mut); + + let (remaining, header) = NpVersionHeader::parse(&adv_mut).unwrap(); + + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(v1_header, remaining).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + // generate a random key pair since we need _some_ public key in our discovery + // credential, even if it winds up going unused + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + + let discovery_credential = V1BroadcastCredential::new(key_seed, metadata_key, private_key) + .derive_discovery_credential::<CryptoProviderImpl>(); + + match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>( + &mut deserialization_arena!().into_allocator(), + &discovery_credential, + ) { + Ok(section) => { + assert_eq!( + expected_error, + DeserializeError::DataElementParseError( + section.collect_data_elements().unwrap_err() + ) + ); + } + Err(e) => assert_eq!( + expected_error, + DeserializeError::IdentityResolutionOrDeserializationError(e), + ), + }; +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/signature_decrypt_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/signature_decrypt_tests.rs new file mode 100644 index 0000000..d843cb0 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/encrypted_section/tests/signature_decrypt_tests.rs
@@ -0,0 +1,589 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use super::*; +use crate::{ + deserialization_arena, + extended::{ + data_elements::TxPowerDataElement, + deserialize::{ + encrypted_section, + section::intermediate::{ + parse_sections, tests::IntermediateSectionExt, CiphertextSection, + }, + DataElement, DataElementParseError, Section, + }, + serialize::{ + AdvBuilder, AdvertisementType, CapacityLimitedVec, SignedEncryptedSectionEncoder, + SingleTypeDataElement, WriteDataElement, + }, + V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, + }, + shared_data::TxPower, + NpVersionHeader, +}; +use crypto_provider::ed25519; +use crypto_provider_default::CryptoProviderImpl; +use np_hkdf::{v1_salt, DerivedSectionKeys}; +use sink::Sink; +use std::{prelude::rust_2021::*, vec}; + +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; + +#[test] +fn deserialize_signature_encrypted_correct_keys_extended_salt() { + let identity_token = V1IdentityToken::from([1; 16]); + let key_seed = [2; 32]; + let section_salt = ExtendedV1Salt::from([3; 16]); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); + + let mut section_builder = adv_builder + .section_builder(SignedEncryptedSectionEncoder::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cm, + )) + .unwrap(); + + let txpower_de = TxPowerDataElement::from(TxPower::try_from(7).unwrap()); + section_builder.add_de(|_| txpower_de.clone()).unwrap(); + + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let adv = adv_builder.into_advertisement(); + + let (after_version_header, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let adv_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(adv_header, after_version_header).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + assert_eq!( + &SignatureEncryptedSection { + contents: EncryptedSectionContents { + adv_header, + format_bytes: &[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN], + salt: section_salt, + identity_token: first_section_identity_token( + section_salt.into(), + after_version_header + ), + // adv header + section len + format + salt + identity token + section_contents: first_section_contents(after_version_header), + total_section_contents_len: contents.contents.total_section_contents_len + }, + }, + contents + ); + + let mut de_bytes = Vec::new(); + de_bytes.extend_from_slice(txpower_de.de_header().serialize().as_slice()); + let _ = txpower_de.write_de_contents(&mut de_bytes); + let de_bytes = de_bytes; + + // plaintext is correct + { + let credential = V1DiscoveryCredential::new( + key_seed, + key_seed_hkdf + .v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + private_key.derive_public_key::<Ed25519ProviderImpl>(), + ); + let signed_identity_resolution_material = + credential.signed_identity_resolution_material::<CryptoProviderImpl>(); + let identity_resolution_contents = + contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>(); + let identity_match = identity_resolution_contents + .try_match::<CryptoProviderImpl>( + &signed_identity_resolution_material.into_raw_resolution_material(), + ) + .unwrap(); + + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let decrypted = + contents.contents.decrypt_ciphertext(&mut allocator, identity_match).unwrap(); + + let nonce: AesCtrNonce = section_salt.compute_nonce::<CryptoProviderImpl>(); + + let sig_payload = SectionSignaturePayload::new( + &[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN], + section_salt.as_slice(), + &nonce, + identity_token.as_slice(), + (de_bytes.len() + crypto_provider::ed25519::SIGNATURE_LENGTH).try_into().unwrap(), + &de_bytes, + ); + + let mut de_and_sig = de_bytes.clone(); + de_and_sig + .extend_from_slice(&sig_payload.sign::<Ed25519ProviderImpl>(&private_key).to_bytes()); + assert_eq!(identity_token, decrypted.identity_token); + assert_eq!(nonce, decrypted.nonce); + assert_eq!(&de_and_sig, decrypted.plaintext_contents); + } + + // deserialization to Section works + { + let credential = V1DiscoveryCredential::new( + key_seed, + key_seed_hkdf + .v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + private_key.derive_public_key::<Ed25519ProviderImpl>(), + ); + let signed_identity_resolution_material = + credential.signed_identity_resolution_material::<CryptoProviderImpl>(); + let signed_verification_material = + credential.signed_verification_material::<CryptoProviderImpl>(); + + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let section = contents + .try_resolve_identity_and_deserialize::<CryptoProviderImpl>( + &mut allocator, + &signed_identity_resolution_material, + &signed_verification_material, + ) + .unwrap(); + + assert_eq!( + DecryptedSection::new( + VerificationMode::Signature, + section_salt.into(), + identity_token, + &de_bytes, + ), + section + ); + let data_elements = section.collect_data_elements().unwrap(); + assert_eq!(data_elements, &[DataElement::new(0.into(), 0x05_u8.into(), &[7])]); + + assert_eq!( + vec![(v1_salt::DataElementOffset::from(0_u8), TxPowerDataElement::DE_TYPE, vec![7u8])], + data_elements + .into_iter() + .map(|de| (de.offset(), de.de_type(), de.contents().to_vec())) + .collect::<Vec<_>>() + ); + } +} + +#[test] +fn deserialize_signature_encrypted_incorrect_aes_key_error() { + // bad aes key -> bad metadata key plaintext + do_bad_deserialize_params::<CryptoProviderImpl>( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + Some([0xFF; 16].into()), + None, + None, + None, + ); +} + +#[test] +fn deserialize_signature_encrypted_incorrect_metadata_key_hmac_key_error() { + // bad metadata key hmac key -> bad calculated metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + None, + Some([0xFF; 32].into()), + None, + None, + ); +} + +#[test] +fn deserialize_signature_encrypted_incorrect_expected_metadata_key_hmac_error() { + // bad expected metadata key mac + do_bad_deserialize_params::<CryptoProviderImpl>( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + None, + None, + Some([0xFF; 32]), + None, + ); +} + +#[test] +fn deserialize_signature_encrypted_incorrect_pub_key_error() { + // a random pub key will lead to signature mismatch + do_bad_deserialize_params::<CryptoProviderImpl>( + SignatureVerificationError::SignatureMismatch.into(), + None, + None, + None, + Some( + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>() + .derive_public_key::<Ed25519ProviderImpl>(), + ), + ); +} + +#[test] +fn deserialize_signature_encrypted_incorrect_salt_error() { + // bad salt -> bad iv -> bad metadata key plaintext + do_bad_deserialize_tampered( + DeserializeError::IdentityResolutionOrDeserializationError( + IdentityResolutionOrDeserializationError::IdentityMatchingError, + ), + None, + |_| {}, + |adv_mut| { + adv_mut[1 + 1 + 1..][..EXTENDED_SALT_LEN].copy_from_slice(&[0xFF; EXTENDED_SALT_LEN]) + }, + ) +} + +#[test] +fn deserialize_signature_encrypted_tampered_signature_error() { + do_bad_deserialize_tampered( + DeserializeError::IdentityResolutionOrDeserializationError( + SignatureVerificationError::SignatureMismatch.into(), + ), + None, + |_| {}, + // flip a bit in the middle of the signature + |adv_mut| { + let len = adv_mut.len(); + adv_mut[len - 30] ^= 0x1 + }, + ) +} + +#[test] +fn deserialize_signature_encrypted_tampered_ciphertext_error() { + do_bad_deserialize_tampered( + DeserializeError::IdentityResolutionOrDeserializationError( + SignatureVerificationError::SignatureMismatch.into(), + ), + None, + |_| {}, + // flip a bit outside of the signature + |adv_mut| { + let len = adv_mut.len(); + adv_mut[len - 1 - 64] ^= 0x1 + }, + ) +} + +#[test] +fn deserialize_signature_encrypted_missing_signature_error() { + let de_len = 2; + do_bad_deserialize_tampered( + DeserializeError::IdentityResolutionOrDeserializationError( + SignatureVerificationError::SignatureMissing.into(), + ), + Some(de_len as u8), + |_| {}, + |adv_mut| { + // chop off signature + adv_mut.truncate(adv_mut.len() - 64); + // fix section length + adv_mut[1 + 1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN..][0] = de_len as u8; + }, + ) +} + +#[test] +fn deserialize_signature_encrypted_des_wont_parse() { + do_bad_deserialize_tampered( + DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd), + Some(2 + 1 + crypto_provider::ed25519::SIGNATURE_LENGTH as u8), + // add an impossible DE + |section| { + section.try_push(0xFF).unwrap(); + }, + |_| {}, + ) +} + +#[test] +fn arena_out_of_space_on_signature_verify() { + let salt: ExtendedV1Salt = [0; 16].into(); + let nonce = salt.compute_nonce::<CryptoProviderImpl>(); + let sig_enc_section = SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + V1AdvHeader::new(0), + &[0], + [0; 16].into(), + [0x00; V1_IDENTITY_TOKEN_LEN].into(), + 1, + &[0x00; 1], + ), + }; + + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let _ = allocator.allocate(250).unwrap(); + + let cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &[0u8; 16].into(), + NonceAndCounter::from_nonce(nonce), + ); + let im: encrypted_section::IdentityMatch<CryptoProviderImpl> = + IdentityMatch { cipher, identity_token: V1IdentityToken([0; 16]), nonce }; + + let signed_verification_material = SignedSectionVerificationMaterial { + public_key: ed25519::PublicKey::from_bytes::<Ed25519ProviderImpl>([0u8; 32]) + .expect("public key should be valid bytes"), + }; + + let _ = sig_enc_section.try_deserialize(&mut allocator, im, &signed_verification_material); +} + +/// Attempt a deserialization that will fail when using the provided parameters for decryption only. +/// `None` means use the correct value for that parameter. +fn do_bad_deserialize_params<C: CryptoProvider>( + error: IdentityResolutionOrDeserializationError<SignatureVerificationError>, + aes_key: Option<crypto_provider::aes::Aes128Key>, + metadata_key_hmac_key: Option<np_hkdf::NpHmacSha256Key>, + expected_metadata_key_hmac: Option<[u8; 32]>, + pub_key: Option<ed25519::PublicKey>, +) { + let metadata_key = V1IdentityToken([1; 16]); + let key_seed = [2; 32]; + let section_salt: v1_salt::ExtendedV1Salt = [3; 16].into(); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); + let private_key = ed25519::PrivateKey::generate::<C::Ed25519>(); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = V1BroadcastCredential::new(key_seed, metadata_key, private_key.clone()); + + let mut section_builder = adv_builder + .section_builder(SignedEncryptedSectionEncoder::new::<C>(section_salt, &broadcast_cm)) + .unwrap(); + + section_builder.add_de_res(|_| TxPower::try_from(2).map(TxPowerDataElement::from)).unwrap(); + + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let adv = adv_builder.into_advertisement(); + + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(v1_header, remaining).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + + let signed_identity_resolution_material = + SignedSectionIdentityResolutionMaterial::from_raw(SectionIdentityResolutionMaterial { + aes_key: aes_key.unwrap_or_else(|| key_seed_hkdf.v1_signature_keys().aes_key()), + + identity_token_hmac_key: *metadata_key_hmac_key + .unwrap_or_else(|| key_seed_hkdf.v1_signature_keys().identity_token_hmac_key()) + .as_bytes(), + expected_identity_token_hmac: expected_metadata_key_hmac.unwrap_or_else(|| { + key_seed_hkdf + .v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&metadata_key.0) + }), + }); + + let signed_verification_material = SignedSectionVerificationMaterial { + public_key: pub_key + .unwrap_or_else(|| private_key.derive_public_key::<Ed25519ProviderImpl>()), + }; + + assert_eq!( + error, + contents + .try_resolve_identity_and_deserialize::<C>( + &mut deserialization_arena!().into_allocator(), + &signed_identity_resolution_material, + &signed_verification_material, + ) + .unwrap_err() + ); +} + +#[derive(Debug, PartialEq)] +enum DeserializeError { + IdentityResolutionOrDeserializationError( + IdentityResolutionOrDeserializationError<SignatureVerificationError>, + ), + DataElementParseError(DataElementParseError), +} + +/// Run a test that mangles the advertisement contents before attempting to deserialize. +/// +/// The section will have a TxPower DE added. +fn do_bad_deserialize_tampered( + expected_error: DeserializeError, + expected_section_de_len: Option<u8>, + mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), + mangle_adv_contents: impl Fn(&mut Vec<u8>), +) { + let identity_token = V1IdentityToken::from([1; V1_IDENTITY_TOKEN_LEN]); + let key_seed = [2; 32]; + let section_salt: v1_salt::ExtendedV1Salt = [3; EXTENDED_SALT_LEN].into(); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); + + let mut section_builder = adv_builder + .section_builder(SignedEncryptedSectionEncoder::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cm, + )) + .unwrap(); + + section_builder.add_de_res(|_| TxPower::try_from(2).map(TxPowerDataElement::from)).unwrap(); + + mangle_section(&mut section_builder.section); + + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let adv = adv_builder.into_advertisement(); + let mut adv_mut = adv.as_slice().to_vec(); + mangle_adv_contents(&mut adv_mut); + + let (after_version_header, header) = NpVersionHeader::parse(&adv_mut).unwrap(); + + let adv_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + + let sections = parse_sections(adv_header, after_version_header).unwrap(); + assert_eq!(1, sections.len()); + + let section = sections.into_iter().next().unwrap(); + let enc_section = section.as_ciphertext().unwrap(); + let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section { + contents + } else { + panic!("incorrect flavor"); + }; + if let Some(len) = expected_section_de_len { + assert_eq!(usize::from(len), contents.contents.section_contents.len()); + } + + let extracted_salt = first_section_salt(after_version_header); + assert_eq!( + &SignatureEncryptedSection { + contents: EncryptedSectionContents { + adv_header, + // extract data from adv buffer in case the caller tampered with things + salt: extracted_salt, + identity_token: first_section_identity_token( + extracted_salt.into(), + after_version_header + ), + section_contents: first_section_contents(after_version_header), + format_bytes: first_section_format(after_version_header), + total_section_contents_len: first_section_contents_len(after_version_header), + }, + }, + contents + ); + + let credential = V1DiscoveryCredential::new( + key_seed, + key_seed_hkdf + .v1_mic_short_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_mic_extended_salt_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + key_seed_hkdf + .v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(&identity_token.0), + private_key.derive_public_key::<Ed25519ProviderImpl>(), + ); + let identity_resolution_material = + credential.signed_identity_resolution_material::<CryptoProviderImpl>(); + let verification_material = credential.signed_verification_material::<CryptoProviderImpl>(); + + match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>( + &mut deserialization_arena!().into_allocator(), + &identity_resolution_material, + &verification_material, + ) { + Ok(section) => { + assert_eq!( + expected_error, + DeserializeError::DataElementParseError( + section.collect_data_elements().unwrap_err() + ), + ); + } + Err(e) => assert_eq!( + expected_error, + DeserializeError::IdentityResolutionOrDeserializationError(e), + ), + }; +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/mod.rs index a208040..c6c7ba4 100644 --- a/nearby/presence/np_adv/src/extended/deserialize/mod.rs +++ b/nearby/presence/np_adv/src/extended/deserialize/mod.rs
@@ -13,265 +13,84 @@ // limitations under the License. //! Deserialization for V1 advertisement contents - #[cfg(any(test, feature = "alloc"))] -extern crate alloc; - -#[cfg(any(test, feature = "alloc", feature = "devtools"))] use alloc::vec::Vec; -use core::array::TryFromSliceError; -use core::fmt::Debug; -use nom::{branch, bytes, combinator, error, multi, number, sequence}; -use strum::IntoEnumIterator as _; +use core::{array::TryFromSliceError, fmt::Debug}; -use array_view::ArrayView; -use crypto_provider::CryptoProvider; -use np_hkdf::v1_salt::{self, V1Salt}; - -use crate::array_vec::ArrayVecOption; -#[cfg(any(feature = "devtools", test))] -use crate::credential::v1::V1DiscoveryCryptoMaterial; -use crate::credential::v1::V1; -use crate::deserialization_arena::ArenaOutOfSpace; -#[cfg(any(feature = "devtools", test))] -use crate::deserialization_arena::DeserializationArenaAllocator; -#[cfg(test)] -use crate::extended::deserialize::encrypted_section::IdentityResolutionOrDeserializationError; -use crate::extended::{NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT}; use crate::{ - de_type::{EncryptedIdentityDataElementType, IdentityDataElementType}, - extended::{ - data_elements::{MIC_ENCRYPTION_SCHEME, SIGNATURE_ENCRYPTION_SCHEME}, - de_type::{DeType, ExtendedDataElementType as _}, - deserialize::encrypted_section::{ - DeserializationError, EncryptedSectionContents, MicEncryptedSection, - MicVerificationError, SignatureEncryptedSection, SignatureVerificationError, - }, - DeLength, ENCRYPTION_INFO_DE_TYPE, NP_ADV_MAX_SECTION_LEN, + array_vec::ArrayVecOption, + credential::{ + book::CredentialBook, + matched::{HasIdentityMatch, MatchedCredential, WithMatchedCredential}, + v1::{V1DiscoveryCryptoMaterial, V1}, }, - HasIdentityMatch, MetadataKey, PlaintextIdentityMode, V1Header, + deserialization_arena::{ArenaOutOfSpace, DeserializationArena, DeserializationArenaAllocator}, + extended::{ + deserialize::{ + data_element::{DataElement, DataElementParseError, DataElementParsingIterator}, + encrypted_section::{ + DeserializationError, MicVerificationError, SectionIdentityResolutionContents, + SignatureVerificationError, + }, + section::intermediate::{ + parse_sections, CiphertextSection, IntermediateSection, PlaintextSection, + }, + }, + salt::MultiSalt, + V1IdentityToken, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, + }, + header::V1AdvHeader, + AdvDeserializationError, AdvDeserializationErrorDetailsHazmat, }; +use crypto_provider::CryptoProvider; +#[cfg(test)] +mod tests; + +pub mod data_element; pub(crate) mod encrypted_section; +pub(crate) mod section; -#[cfg(test)] -mod parse_tests; +/// Provides deserialization APIs which expose more of the internals, suitable for use only in +/// dev tools. +#[cfg(feature = "devtools")] +pub mod dev_tools; -#[cfg(test)] -mod section_tests; +/// Deserialize and decrypt the contents of a v1 adv after the version header +pub(crate) fn deser_decrypt_v1<'adv, 'cred, B, P>( + arena: DeserializationArena<'adv>, + cred_book: &'cred B, + remaining: &'adv [u8], + header: V1AdvHeader, +) -> Result<V1AdvertisementContents<'adv, B::Matched>, AdvDeserializationError> +where + B: CredentialBook<'cred>, + P: CryptoProvider, +{ + let mut sections_in_processing = + SectionsInProcessing::<'_, B::Matched>::from_advertisement_contents::<P>( + header, remaining, + )?; -#[cfg(test)] -mod test_stubs; + let mut allocator = arena.into_allocator(); -/// Parse into [IntermediateSection]s, exposing the underlying parsing errors. -/// Consumes all of `adv_body`. -pub(crate) fn parse_sections( - adv_header: V1Header, - adv_body: &[u8], -) -> Result< - ArrayVecOption<IntermediateSection, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT>, - nom::Err<error::Error<&[u8]>>, -> { - combinator::all_consuming(branch::alt(( - // Public advertisement - multi::fold_many_m_n( - 1, - NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, - IntermediateSection::parser_public_section(), - ArrayVecOption::default, - |mut acc, item| { - acc.push(item); - acc - }, - ), - // Encrypted advertisement - multi::fold_many_m_n( - 1, - NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, - IntermediateSection::parser_encrypted_with_header(adv_header), - ArrayVecOption::default, - |mut acc, item| { - acc.push(item); - acc - }, - ), - )))(adv_body) - .map(|(_rem, sections)| sections) -} - -/// A partially processed section that hasn't been decrypted (if applicable) yet. -#[derive(PartialEq, Eq, Debug)] -pub(crate) enum IntermediateSection<'a> { - /// A section that was not encrypted, e.g. a public identity or no-identity section. - Plaintext(PlaintextSection<'a>), - /// A section whose contents were encrypted, e.g. a private identity section. - Ciphertext(CiphertextSection<'a>), -} - -impl<'a> IntermediateSection<'a> { - fn parser_public_section( - ) -> impl Fn(&'a [u8]) -> nom::IResult<&'a [u8], IntermediateSection<'a>> { - move |adv_body| { - let (remaining, section_contents_len) = - combinator::verify(number::complete::u8, |sec_len| { - *sec_len as usize <= NP_ADV_MAX_SECTION_LEN && *sec_len as usize > 0 - })(adv_body)?; - - // Section structure possibilities: - // - Public Identity DE, all other DEs - let parse_public_identity = combinator::map( - // 1 starting offset because of public identity before it - sequence::tuple((PublicIdentity::parse, nom::combinator::rest)), - // move closure to copy section_len into scope - move |(_identity, rest)| { - IntermediateSection::Plaintext(PlaintextSection::new( - PlaintextIdentityMode::Public, - SectionContents::new( - /* section_header */ section_contents_len, - rest, - 1, - ), - )) - }, - ); - combinator::map_parser( - bytes::complete::take(section_contents_len), - // Guarantee we consume all of the section (not all of the adv body) - // Note: `all_consuming` should never fail, since we used the `rest` parser above. - combinator::all_consuming(parse_public_identity), - )(remaining) + // Hot loop + // We assume that iterating credentials is more expensive than iterating sections + for (crypto_material, match_data) in cred_book.v1_iter() { + sections_in_processing + .try_decrypt_with_credential::<_, P>(&mut allocator, crypto_material, match_data) + .expect(concat!( + "Should not run out of space because DeserializationArenaAllocator is big ", + "enough to hold a single advertisement, and we exit immediately upon ", + "successful decryption", + )); + if sections_in_processing.resolved_all_identities() { + // No need to consider the other credentials + break; } } - - fn parser_encrypted_with_header( - adv_header: V1Header, - ) -> impl Fn(&'a [u8]) -> nom::IResult<&[u8], IntermediateSection> { - move |adv_body| { - let (remaining, section_contents_len) = - combinator::verify(number::complete::u8, |sec_len| { - *sec_len as usize <= NP_ADV_MAX_SECTION_LEN && *sec_len as usize > 0 - })(adv_body)?; - - // Section structure possibilities: - // - Encryption information, non-public Identity header, ciphertext - // - Encryption information, non-public Identity header, ciphertext, MIC - - let parse_encrypted_identity = combinator::map( - sequence::tuple(( - EncryptionInfo::parse_signature, - combinator::verify( - combinator::consumed(sequence::tuple(( - EncryptedIdentityMetadata::parser_at_offset( - v1_salt::DataElementOffset::from(1), - ), - combinator::rest, - ))), - // should be trivially true since section length was checked above, - // but this is an invariant for EncryptedSection, so we double check - |(identity_and_ciphertext, _tuple)| { - (EncryptedIdentityMetadata::TOTAL_DE_LEN..=NP_ADV_MAX_SECTION_LEN) - .contains(&identity_and_ciphertext.len()) - }, - ), - )), - move |(encryption_info, (identity_and_ciphertext, (identity, _des_ciphertext)))| { - // skip identity de header -- rest of that de is ciphertext - let to_skip = identity.header_bytes.len(); - IntermediateSection::Ciphertext(CiphertextSection::SignatureEncryptedIdentity( - SignatureEncryptedSection { - contents: EncryptedSectionContents::new( - adv_header, - section_contents_len, - encryption_info, - identity, - &identity_and_ciphertext[to_skip..], - ), - }, - )) - }, - ); - - let parse_mic_encrypted_identity = combinator::map( - sequence::tuple(( - EncryptionInfo::parse_mic, - combinator::verify( - combinator::consumed(sequence::tuple(( - EncryptedIdentityMetadata::parser_at_offset( - v1_salt::DataElementOffset::from(1), - ), - combinator::rest, - ))), - // Should be trivially true since section length was checked above, - // but this is an invariant for MicEncryptedSection, so we double check. - // Also verify that there is enough space at the end to contain a valid-length MIC. - |(identity_ciphertext_and_mic, _tuple)| { - (EncryptedIdentityMetadata::TOTAL_DE_LEN + SectionMic::CONTENTS_LEN - ..=NP_ADV_MAX_SECTION_LEN) - .contains(&identity_ciphertext_and_mic.len()) - }, - ), - )), - move |( - encryption_info, - (identity_ciphertext_and_mic, (identity, _ciphertext_and_mic)), - )| { - // should not panic since we have already ensured a valid length - let (identity_and_ciphertext, mic) = identity_ciphertext_and_mic - .split_at(identity_ciphertext_and_mic.len() - SectionMic::CONTENTS_LEN); - // skip identity de header -- rest of that de is ciphertext - let to_skip = identity.header_bytes.len(); - IntermediateSection::Ciphertext(CiphertextSection::MicEncryptedIdentity( - MicEncryptedSection { - contents: EncryptedSectionContents::new( - adv_header, - section_contents_len, - encryption_info, - identity, - &identity_and_ciphertext[to_skip..], - ), - mic: mic.try_into().unwrap_or_else(|_| { - panic!("{} is a valid length", SectionMic::CONTENTS_LEN) - }), - }, - )) - }, - ); - - combinator::map_parser( - bytes::complete::take(section_contents_len), - // guarantee we consume all of the section (not all of the adv body) - combinator::all_consuming(branch::alt(( - parse_mic_encrypted_identity, - parse_encrypted_identity, - ))), - )(remaining) - } - } -} - -#[derive(PartialEq, Eq, Debug)] -struct SectionContents<'adv> { - section_header: u8, - de_region_excl_identity: &'adv [u8], - data_element_start_offset: u8, -} - -impl<'adv> SectionContents<'adv> { - fn new( - section_header: u8, - de_region_excl_identity: &'adv [u8], - data_element_start_offset: u8, - ) -> Self { - Self { section_header, de_region_excl_identity, data_element_start_offset } - } - - fn iter_data_elements(&self) -> DataElementParsingIterator<'adv> { - DataElementParsingIterator { - input: self.de_region_excl_identity, - offset: self.data_element_start_offset, - } - } + Ok(sections_in_processing.finished_with_decryption_attempts()) } /// A section deserialized from a V1 advertisement. @@ -295,83 +114,24 @@ } } -/// A plaintext section deserialized from a V1 advertisement. -#[derive(PartialEq, Eq, Debug)] -pub struct PlaintextSection<'adv> { - identity: PlaintextIdentityMode, - contents: SectionContents<'adv>, -} - -impl<'adv> PlaintextSection<'adv> { - fn new(identity: PlaintextIdentityMode, contents: SectionContents<'adv>) -> Self { - Self { identity, contents } - } - - /// The identity mode for the section. - /// - /// Since plaintext sections do not use encryption, they cannot be matched to a single identity, - /// and only have a mode (no identity or public). - pub fn identity(&self) -> PlaintextIdentityMode { - self.identity - } -} - -impl<'adv> Section<'adv, DataElementParseError> for PlaintextSection<'adv> { - type Iterator = DataElementParsingIterator<'adv>; - - fn iter_data_elements(&self) -> Self::Iterator { - self.contents.iter_data_elements() - } -} - -/// A byte buffer the size of a V1 salt. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct RawV1Salt(pub(crate) [u8; 16]); - -impl RawV1Salt { - /// Returns the raw salt bytes as a vec. - #[cfg(feature = "devtools")] - pub fn to_vec(&self) -> Vec<u8> { - self.0.to_vec() - } -} - -impl<C: CryptoProvider> From<RawV1Salt> for V1Salt<C> { - fn from(raw_salt: RawV1Salt) -> Self { - raw_salt.0.into() - } -} - -impl<C: CryptoProvider> From<V1Salt<C>> for RawV1Salt { - fn from(salt: V1Salt<C>) -> Self { - RawV1Salt(salt.into_array()) - } -} - /// Fully-parsed and verified decrypted contents from an encrypted section. #[derive(Debug, PartialEq, Eq)] pub struct DecryptedSection<'adv> { - identity_type: EncryptedIdentityDataElementType, verification_mode: VerificationMode, - metadata_key: MetadataKey, - salt: RawV1Salt, - contents: SectionContents<'adv>, + identity_token: V1IdentityToken, + salt: MultiSalt, + /// Decrypted DE data, excluding any encoder suffix + plaintext: &'adv [u8], } impl<'adv> DecryptedSection<'adv> { fn new( - identity_type: EncryptedIdentityDataElementType, verification_mode: VerificationMode, - metadata_key: MetadataKey, - salt: RawV1Salt, - contents: SectionContents<'adv>, + salt: MultiSalt, + identity_token: V1IdentityToken, + plaintext: &'adv [u8], ) -> Self { - Self { identity_type, verification_mode, metadata_key, salt, contents } - } - - /// The type of identity DE used in the section. - pub fn identity_type(&self) -> EncryptedIdentityDataElementType { - self.identity_type + Self { verification_mode, identity_token, salt, plaintext } } /// The verification mode used in the section. @@ -379,16 +139,26 @@ self.verification_mode } - /// The salt used for decryption of this advertisement. - pub fn salt(&self) -> RawV1Salt { - self.salt + /// The identity token extracted from the section + pub fn identity_token(&self) -> &V1IdentityToken { + &self.identity_token + } + + /// The salt used for decryption of this section. + pub fn salt(&self) -> &MultiSalt { + &self.salt + } + + #[cfg(test)] + pub(crate) fn plaintext(&self) -> &'adv [u8] { + self.plaintext } } impl<'adv> HasIdentityMatch for DecryptedSection<'adv> { type Version = V1; - fn metadata_key(&self) -> MetadataKey { - self.metadata_key + fn identity_token(&self) -> V1IdentityToken { + self.identity_token } } @@ -396,88 +166,7 @@ type Iterator = DataElementParsingIterator<'adv>; fn iter_data_elements(&self) -> Self::Iterator { - self.contents.iter_data_elements() - } -} - -#[derive(PartialEq, Eq, Debug)] -pub(crate) enum CiphertextSection<'a> { - SignatureEncryptedIdentity(SignatureEncryptedSection<'a>), - MicEncryptedIdentity(MicEncryptedSection<'a>), -} - -impl<'a> CiphertextSection<'a> { - /// Tries to match this section's identity using the given crypto-material, - /// and if successful, tries to decrypt this section. - #[cfg(test)] - pub(crate) fn try_resolve_identity_and_deserialize<C, P>( - &'a self, - allocator: &mut DeserializationArenaAllocator<'a>, - crypto_material: &C, - ) -> Result<DecryptedSection<'a>, SectionDeserializeError> - where - C: V1DiscoveryCryptoMaterial, - P: CryptoProvider, - { - match self { - CiphertextSection::SignatureEncryptedIdentity(contents) => { - let identity_resolution_material = - crypto_material.signed_identity_resolution_material::<P>(); - let verification_material = crypto_material.signed_verification_material::<P>(); - - contents - .try_resolve_identity_and_deserialize::<P>( - allocator, - &identity_resolution_material, - &verification_material, - ) - .map_err(|e| e.into()) - } - CiphertextSection::MicEncryptedIdentity(contents) => { - let identity_resolution_material = - crypto_material.unsigned_identity_resolution_material::<P>(); - let verification_material = crypto_material.unsigned_verification_material::<P>(); - - contents - .try_resolve_identity_and_deserialize::<P>( - allocator, - &identity_resolution_material, - &verification_material, - ) - .map_err(|e| e.into()) - } - } - } - - /// Try decrypting into some raw bytes given some raw unsigned crypto-material. - #[cfg(feature = "devtools")] - pub(crate) fn try_resolve_identity_and_decrypt< - C: V1DiscoveryCryptoMaterial, - P: CryptoProvider, - >( - &self, - allocator: &mut DeserializationArenaAllocator<'a>, - crypto_material: &C, - ) -> Option<Result<ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, ArenaOutOfSpace>> { - match self { - CiphertextSection::SignatureEncryptedIdentity(x) => { - let identity_resolution_material = - crypto_material.signed_identity_resolution_material::<P>(); - x.try_resolve_identity_and_decrypt::<P>(allocator, &identity_resolution_material) - } - CiphertextSection::MicEncryptedIdentity(x) => { - let identity_resolution_material = - crypto_material.unsigned_identity_resolution_material::<P>(); - x.try_resolve_identity_and_decrypt::<P>(allocator, &identity_resolution_material) - } - } - } - - pub(crate) fn contents(&self) -> &EncryptedSectionContents<'a> { - match self { - CiphertextSection::SignatureEncryptedIdentity(x) => &x.contents, - CiphertextSection::MicEncryptedIdentity(x) => &x.contents, - } + DataElementParsingIterator::new(self.plaintext) } } @@ -493,34 +182,6 @@ ArenaOutOfSpace, } -#[cfg(test)] -impl From<IdentityResolutionOrDeserializationError<MicVerificationError>> - for SectionDeserializeError -{ - fn from(error: IdentityResolutionOrDeserializationError<MicVerificationError>) -> Self { - match error { - IdentityResolutionOrDeserializationError::IdentityMatchingError => { - Self::IncorrectCredential - } - IdentityResolutionOrDeserializationError::DeserializationError(e) => e.into(), - } - } -} - -#[cfg(test)] -impl From<IdentityResolutionOrDeserializationError<SignatureVerificationError>> - for SectionDeserializeError -{ - fn from(error: IdentityResolutionOrDeserializationError<SignatureVerificationError>) -> Self { - match error { - IdentityResolutionOrDeserializationError::IdentityMatchingError => { - Self::IncorrectCredential - } - IdentityResolutionOrDeserializationError::DeserializationError(e) => e.into(), - } - } -} - impl From<DeserializationError<MicVerificationError>> for SectionDeserializeError { fn from(mic_deserialization_error: DeserializationError<MicVerificationError>) -> Self { match mic_deserialization_error { @@ -548,191 +209,226 @@ } } -/// An iterator that parses the given data elements iteratively. In environments where memory is -/// not severely constrained, it is usually safer to collect this into `Result<Vec<DataElement>>` -/// so the validity of the whole advertisement can be checked before proceeding with further -/// processing. -#[derive(Debug)] -pub struct DataElementParsingIterator<'adv> { - input: &'adv [u8], - // The index of the data element this is currently at - offset: u8, +/// A ciphertext section which has not yet been +/// resolved to an identity, but for which some +/// `SectionIdentityResolutionContents` have been +/// pre-computed for speedy identity-resolution. +struct ResolvableCiphertextSection<'a> { + identity_resolution_contents: SectionIdentityResolutionContents, + ciphertext_section: CiphertextSection<'a>, } -/// The error that may arise while parsing data elements. -#[derive(Debug, PartialEq, Eq)] -pub enum DataElementParseError { - /// Only one identity data element is allowed in an advertisement, but a duplicate is found - /// while parsing. - DuplicateIdentityDataElement, - /// Unexpected data found after the end of the data elements portion. This means either the - /// parser was fed with additional data (it should only be given the bytes within a section, - /// not the whole advertisement), or the length field in the header of the data element is - /// malformed. - UnexpectedDataAfterEnd, - /// There are too many data elements in the advertisement. The maximum number supported by the - /// current parsing logic is 255. - TooManyDataElements, - /// A parse error is returned during nom. - NomError(nom::error::ErrorKind), +/// A collection of possibly-deserialized sections which are separated according +/// to whether/not they're intermediate encrypted sections (of either type) +/// or fully-deserialized, with a running count of the number of malformed sections. +/// Each potentially-valid section is tagged with a 0-based index derived from the original +/// section ordering as they appeared within the original advertisement to ensure +/// that the fully-deserialized advertisement may be correctly reconstructed. +struct SectionsInProcessing<'adv, M: MatchedCredential> { + deserialized_sections: ArrayVecOption< + (usize, V1DeserializedSection<'adv, M>), + { NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT }, + >, + encrypted_sections: ArrayVecOption< + (usize, ResolvableCiphertextSection<'adv>), + { NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT }, + >, + malformed_sections_count: usize, } -impl<'adv> Iterator for DataElementParsingIterator<'adv> { - type Item = Result<DataElement<'adv>, DataElementParseError>; - - fn next(&mut self) -> Option<Self::Item> { - match ProtoDataElement::parse(self.input) { - Ok((rem, pde)) => { - if !IdentityDataElementType::iter().all(|t| t.type_code() != pde.header.de_type) { - return Some(Err(DataElementParseError::DuplicateIdentityDataElement)); +impl<'adv, M: MatchedCredential> SectionsInProcessing<'adv, M> { + /// Attempts to parse a V1 advertisement's contents after the version header + /// into a collection of not-yet-fully-deserialized sections which may + /// require credentials to be decrypted. + fn from_advertisement_contents<C: CryptoProvider>( + header: V1AdvHeader, + remaining: &'adv [u8], + ) -> Result<Self, AdvDeserializationError> { + let int_sections = + parse_sections(header, remaining).map_err(|_| AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError, + })?; + let mut deserialized_sections = ArrayVecOption::default(); + let mut encrypted_sections = ArrayVecOption::default(); + // keep track of ordering for later sorting during `self.finished_with_decryption_attempts()`. + for (idx, s) in int_sections.into_iter().enumerate() { + match s { + IntermediateSection::Plaintext(p) => { + deserialized_sections.push((idx, V1DeserializedSection::Plaintext(p))) } - self.input = rem; - let current_offset = self.offset; - self.offset = if let Some(offset) = self.offset.checked_add(1) { - offset - } else { - return Some(Err(DataElementParseError::TooManyDataElements)); - }; - Some(Ok(pde.into_data_element(v1_salt::DataElementOffset::from(current_offset)))) - } - Err(nom::Err::Failure(e)) => Some(Err(DataElementParseError::NomError(e.code))), - Err(nom::Err::Incomplete(_)) => { - panic!("Should always complete since we are parsing using the `nom::complete` APIs") - } - Err(nom::Err::Error(_)) => { - // nom `Error` is recoverable, it usually means we should move on the parsing the - // next section. There is nothing after data elements within a section, so we just - // check that there is no remaining data. - if !self.input.is_empty() { - return Some(Err(DataElementParseError::UnexpectedDataAfterEnd)); + IntermediateSection::Ciphertext(ciphertext_section) => { + let identity_resolution_contents = + ciphertext_section.identity_resolution_contents::<C>(); + let resolvable_ciphertext_section = ResolvableCiphertextSection { + identity_resolution_contents, + ciphertext_section, + }; + encrypted_sections.push((idx, resolvable_ciphertext_section)); } - None } } + Ok(Self { deserialized_sections, encrypted_sections, malformed_sections_count: 0 }) } -} -/// Deserialize-specific version of a DE header that incorporates the header length. -/// This is needed for encrypted identities that need to construct a slice of everything in the -/// section following the identity DE header. -#[derive(Debug, PartialEq, Eq, Clone)] -pub(crate) struct DeHeader { - /// The original bytes of the header, at most 6 bytes long (1 byte len, 5 bytes type) - pub(crate) header_bytes: ArrayView<u8, 6>, - pub(crate) de_type: DeType, - pub(crate) contents_len: DeLength, -} + /// Returns true iff we have resolved all sections to identities. + fn resolved_all_identities(&self) -> bool { + self.encrypted_sections.is_empty() + } -impl DeHeader { - pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], DeHeader> { - // 1-byte header: 0b0LLLTTTT - let parse_single_byte_de_header = - combinator::map_opt::<&[u8], _, DeHeader, error::Error<&[u8]>, _, _>( - combinator::consumed(combinator::map_res( - combinator::verify(number::complete::u8, |&b| !hi_bit_set(b)), - |b| { - // L bits - let len = (b >> 4) & 0x07; - // T bits - let de_type = ((b & 0x0F) as u32).into(); - - len.try_into().map(|l| (l, de_type)) - }, - )), - |(header_bytes, (len, de_type))| { - ArrayView::try_from_slice(header_bytes).map(|header_bytes| DeHeader { - header_bytes, - contents_len: len, - de_type, - }) + /// Runs through all of the encrypted sections in processing, and attempts + /// to use the given credential to decrypt them. Suitable for situations + /// where iterating over credentials is relatively slow compared to + /// the cost of iterating over sections-in-memory. + fn try_decrypt_with_credential<C: V1DiscoveryCryptoMaterial, P: CryptoProvider>( + &mut self, + arena: &mut DeserializationArenaAllocator<'adv>, + crypto_material: C, + match_data: M, + ) -> Result<(), ArenaOutOfSpace> { + let mut i = 0; + while i < self.encrypted_sections.len() { + let (section_idx, section): &(usize, ResolvableCiphertextSection) = + &self.encrypted_sections[i]; + // Fast-path: Check for an identity match, ignore if there's no identity match. + let identity_resolution_contents = §ion.identity_resolution_contents; + let identity_resolution_material = match §ion.ciphertext_section { + CiphertextSection::MicEncrypted(m) => match m.contents.salt { + MultiSalt::Short(_) => crypto_material + .mic_short_salt_identity_resolution_material::<P>() + .into_raw_resolution_material(), + MultiSalt::Extended(_) => crypto_material + .mic_extended_salt_identity_resolution_material::<P>() + .into_raw_resolution_material(), }, - ); - // multi-byte headers: 0b1LLLLLLL (0b1TTTTTTT)* 0b0TTTTTTT - // leading 1 in first byte = multibyte format - // leading 1 in subsequent bytes = there is at least 1 more type bytes - // leading 0 = this is the last header byte - // 127-bit length, effectively infinite type bit length + CiphertextSection::SignatureEncrypted(_) => crypto_material + .signed_identity_resolution_material::<P>() + .into_raw_resolution_material(), + }; + match identity_resolution_contents.try_match::<P>(&identity_resolution_material) { + None => { + // Try again with another section + i += 1; + continue; + } + Some(identity_match) => { + // The identity matched, so now we need to more closely scrutinize + // the provided ciphertext. Try to decrypt and parse the section. + let deserialization_result = match §ion.ciphertext_section { + CiphertextSection::SignatureEncrypted(c) => c + .try_deserialize( + arena, + identity_match, + &crypto_material.signed_verification_material::<P>(), + ) + .map_err(SectionDeserializeError::from), + CiphertextSection::MicEncrypted(c) => c + .try_deserialize(arena, identity_match, &crypto_material) + .map_err(SectionDeserializeError::from), + }; + match deserialization_result { + Ok(s) => { + self.deserialized_sections.push(( + *section_idx, + V1DeserializedSection::Decrypted(WithMatchedCredential::new( + match_data.clone(), + crypto_material.metadata_nonce::<P>(), + s, + )), + )); + } + Err(e) => match e { + SectionDeserializeError::IncorrectCredential => { + // keep it around to try with another credential + i += 1; + continue; + } + SectionDeserializeError::ParseError => { + // the credential worked, but the section itself was bogus + self.malformed_sections_count += 1; + } + SectionDeserializeError::ArenaOutOfSpace => { + return Err(ArenaOutOfSpace); + } + }, + } + // By default, if we have an identity match, assume that decrypting the section worked, + // or that the section was somehow invalid. + // We don't care about maintaining order, so use O(1) remove + let _ = self.encrypted_sections.swap_remove(i); + // don't advance i -- it now points to a new element + } + } + } + Ok(()) + } - // It's conceivable to have non-canonical extended type sequences where 1 or more leading - // bytes don't have any bits set (other than the marker hi bit), thereby contributing nothing - // to the final value. - // To prevent that, we require that either there be only 1 type byte, or that the first of the - // multiple type bytes must have a value bit set. It's OK to have no value bits in subsequent - // type bytes. + /// Packages the current state of the deserialization process into a + /// `V1AdvertisementContents` representing a fully-deserialized V1 advertisement. + /// + /// This method should only be called after all sections were either successfully + /// decrypted or have had all relevant credentials checked against + /// them without obtaining a successful identity-match and/or subsequent + /// cryptographic verification of the section contents. + fn finished_with_decryption_attempts(mut self) -> V1AdvertisementContents<'adv, M> { + // Invalid sections = malformed sections + number of encrypted sections + // which we could not manage to decrypt with any of our credentials + let invalid_sections_count = self.malformed_sections_count + self.encrypted_sections.len(); - let parse_ext_de_header = combinator::map_opt( - combinator::consumed(sequence::pair( - // length byte w/ leading 1 - combinator::map_res( - combinator::verify(number::complete::u8::<&[u8], _>, |&b| hi_bit_set(b)), - // snag the lower 7 bits - |b| (b & 0x7F).try_into(), - ), - branch::alt(( - // 1 type byte case - combinator::recognize( - // 0-hi-bit type code byte - combinator::verify(number::complete::u8, |&b| !hi_bit_set(b)), - ), - // multiple type byte case: leading type byte must have at least 1 value bit - combinator::recognize(sequence::tuple(( - // hi bit and at least 1 value bit, otherwise it would be non-canonical - combinator::verify(number::complete::u8, |&b| { - hi_bit_set(b) && (b & 0x7F != 0) - }), - // 0-3 1-hi-bit type code bytes with any bit pattern. Max is 3 since two 7 - // bit type chunks are processed before and after this, for a total of 5, - // and that's as many 7-bit chunks as are needed to support a 32-bit type. - bytes::complete::take_while_m_n(0, 3, hi_bit_set), - // final 0-hi-bit type code byte - combinator::verify(number::complete::u8, |&b| !hi_bit_set(b)), - ))), - )), - )), - |(header_bytes, (len, type_bytes))| { - // snag the low 7 bits of each type byte and accumulate - - type_bytes - .iter() - .try_fold(0_u32, |accum, b| { - accum.checked_shl(7).map(|n| n + ((b & 0x7F) as u32)) - }) - .and_then(|type_code| { - ArrayView::try_from_slice(header_bytes).map(|header_bytes| DeHeader { - header_bytes, - contents_len: len, - de_type: type_code.into(), - }) - }) - }, - ); - - branch::alt((parse_single_byte_de_header, parse_ext_de_header))(input) + // Put the deserialized sections back into the original ordering for + // the returned `V1AdvertisementContents` + // (Note: idx is unique, so unstable sort is ok) + self.deserialized_sections.sort_unstable_by_key(|(idx, _section)| *idx); + let ordered_sections = self.deserialized_sections.into_iter().map(|(_idx, s)| s).collect(); + V1AdvertisementContents::new(ordered_sections, invalid_sections_count) } } -/// An intermediate stage in parsing a [DataElement] that lacks `offset`. +/// The contents of a deserialized and decrypted V1 advertisement. #[derive(Debug, PartialEq, Eq)] -struct ProtoDataElement<'d> { - header: DeHeader, - /// `len()` must equal `header.contents_len` - contents: &'d [u8], +pub struct V1AdvertisementContents<'adv, M: MatchedCredential> { + sections: ArrayVecOption<V1DeserializedSection<'adv, M>, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT>, + invalid_sections: usize, } -impl<'d> ProtoDataElement<'d> { - fn parse(input: &[u8]) -> nom::IResult<&[u8], ProtoDataElement> { - let (remaining, header) = DeHeader::parse(input)?; - let len = header.contents_len; - combinator::map(bytes::complete::take(len.as_u8()), move |slice| { - let header_clone = header.clone(); - ProtoDataElement { header: header_clone, contents: slice } - })(remaining) +impl<'adv, M: MatchedCredential> V1AdvertisementContents<'adv, M> { + fn new( + sections: ArrayVecOption< + V1DeserializedSection<'adv, M>, + NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, + >, + invalid_sections: usize, + ) -> Self { + Self { sections, invalid_sections } } - fn into_data_element(self, offset: v1_salt::DataElementOffset) -> DataElement<'d> { - DataElement { offset, de_type: self.header.de_type, contents: self.contents } + /// Destructures this V1 advertisement into just the sections + /// which could be successfully deserialized and decrypted + pub fn into_sections( + self, + ) -> ArrayVecOption<V1DeserializedSection<'adv, M>, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT> { + self.sections } + + /// The sections that could be successfully deserialized and decrypted + pub fn sections(&self) -> impl ExactSizeIterator<Item = &V1DeserializedSection<M>> { + self.sections.iter() + } + + /// The number of sections that could not be parsed or decrypted. + pub fn invalid_sections_count(&self) -> usize { + self.invalid_sections + } +} + +/// Advertisement content that was either already plaintext or has been decrypted. +#[derive(Debug, PartialEq, Eq)] +pub enum V1DeserializedSection<'adv, M: MatchedCredential> { + /// Section that was plaintext in the original advertisement + Plaintext(PlaintextSection<'adv>), + /// Section that was ciphertext in the original advertisement, and has been decrypted + /// with the credential in the [MatchedCredential] + Decrypted(WithMatchedCredential<M, DecryptedSection<'adv>>), } /// The level of integrity protection in an encrypted section @@ -750,125 +446,13 @@ Signature, } -/// The identity used to successfully decrypt and validate an encrypted section -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct EncryptedSectionIdentity { - identity_type: EncryptedIdentityDataElementType, - validation_mode: VerificationMode, - metadata_key: MetadataKey, -} - -impl EncryptedSectionIdentity { - /// The type of identity DE used in the section - pub fn identity_type(&self) -> EncryptedIdentityDataElementType { - self.identity_type - } - /// The validation mode used when decrypting and verifying the section - pub fn verification_mode(&self) -> VerificationMode { - self.validation_mode - } - /// The decrypted metadata key from the section's identity DE - pub fn metadata_key(&self) -> MetadataKey { - self.metadata_key - } -} - -/// A deserialized data element in a section. -/// -/// The DE has been processed to the point of exposing a DE type and its contents as a `&[u8]`, but -/// no DE-type-specific processing has been performed. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct DataElement<'adv> { - offset: v1_salt::DataElementOffset, - de_type: DeType, - contents: &'adv [u8], -} - -impl<'adv> DataElement<'adv> { - /// The offset of the DE in its containing Section. - /// - /// Used with the section salt to derive per-DE salt. - pub fn offset(&self) -> v1_salt::DataElementOffset { - self.offset - } - /// The type of the DE - pub fn de_type(&self) -> DeType { - self.de_type - } - /// The contents of the DE - pub fn contents(&self) -> &'adv [u8] { - self.contents - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub(crate) struct EncryptionInfo { - pub bytes: [u8; 19], -} - -impl EncryptionInfo { - // 2-byte header, 1-byte encryption scheme, 16-byte salt - pub(crate) const TOTAL_DE_LEN: usize = 19; - const CONTENTS_LEN: usize = 17; - const ENCRYPTION_INFO_SCHEME_MASK: u8 = 0b01111000; - - fn parse_signature(input: &[u8]) -> nom::IResult<&[u8], EncryptionInfo> { - Self::parser_for_scheme(SIGNATURE_ENCRYPTION_SCHEME)(input) - } - - fn parse_mic(input: &[u8]) -> nom::IResult<&[u8], EncryptionInfo> { - Self::parser_for_scheme(MIC_ENCRYPTION_SCHEME)(input) - } - - fn parser_for_scheme( - expected_scheme: u8, - ) -> impl Fn(&[u8]) -> nom::IResult<&[u8], EncryptionInfo> { - move |input| { - combinator::map_res( - combinator::consumed(combinator::map_parser( - combinator::map( - combinator::verify(ProtoDataElement::parse, |de| { - de.header.de_type == ENCRYPTION_INFO_DE_TYPE - && de.contents.len() == Self::CONTENTS_LEN - }), - |de| de.contents, - ), - sequence::tuple(( - combinator::verify(number::complete::be_u8, |scheme: &u8| { - expected_scheme == (Self::ENCRYPTION_INFO_SCHEME_MASK & scheme) - }), - bytes::complete::take(16_usize), - )), - )), - |(bytes, _contents)| bytes.try_into(), - )(input) - } - } - - fn salt(&self) -> RawV1Salt { - RawV1Salt( - self.bytes[Self::TOTAL_DE_LEN - 16..] - .try_into() - .expect("a 16 byte slice will always fit into a 16 byte array"), - ) - } -} - -impl TryFrom<&[u8]> for EncryptionInfo { - type Error = TryFromSliceError; - - fn try_from(value: &[u8]) -> Result<Self, Self::Error> { - value.try_into().map(|fixed_bytes: [u8; 19]| Ok(Self { bytes: fixed_bytes }))? - } -} - #[derive(PartialEq, Eq, Debug)] pub(crate) struct SectionMic { - mic: [u8; 16], + mic: [u8; Self::CONTENTS_LEN], } impl SectionMic { - // 16-byte metadata key + /// 16-byte MIC pub(crate) const CONTENTS_LEN: usize = 16; } @@ -887,59 +471,6 @@ } } -#[derive(PartialEq, Eq, Debug)] -struct PublicIdentity; - -impl PublicIdentity { - fn parse(input: &[u8]) -> nom::IResult<&[u8], PublicIdentity> { - combinator::map( - combinator::verify(DeHeader::parse, |deh| { - deh.de_type == IdentityDataElementType::Public.type_code() - && deh.contents_len.as_u8() == 0 - }), - |_| PublicIdentity, - )(input) - } -} - -pub(crate) const IDENTITY_HEADER_LEN: usize = 2; - -/// Parsed form of an encrypted identity DE before its contents are decrypted. -/// Metadata key is stored in the enclosing section. -#[derive(PartialEq, Eq, Debug)] -pub(crate) struct EncryptedIdentityMetadata { - pub(crate) offset: v1_salt::DataElementOffset, - /// The original DE header from the advertisement. - /// Encrypted identity should always be a len=2 header. - pub(crate) header_bytes: [u8; IDENTITY_HEADER_LEN], - pub(crate) identity_type: EncryptedIdentityDataElementType, -} - -impl EncryptedIdentityMetadata { - // 2-byte header, 16-byte metadata key - pub(crate) const TOTAL_DE_LEN: usize = 18; - - /// Returns a parser function that parses an [`EncryptedIdentityMetadata`] using the provided DE `offset`. - fn parser_at_offset( - offset: v1_salt::DataElementOffset, - ) -> impl Fn(&[u8]) -> nom::IResult<&[u8], EncryptedIdentityMetadata> { - move |input| { - combinator::map_opt(ProtoDataElement::parse, |de| { - EncryptedIdentityDataElementType::from_type_code(de.header.de_type).and_then( - |identity_type| { - de.header.header_bytes.as_slice().try_into().ok().and_then(|header_bytes| { - de.contents.try_into().ok().map(|_metadata_key_ciphertext: [u8; 16]| { - // ensure the ciphertext is the right size, then discard - EncryptedIdentityMetadata { header_bytes, offset, identity_type } - }) - }) - }, - ) - })(input) - } - } -} - fn hi_bit_set(b: u8) -> bool { b & 0x80 > 0 }
diff --git a/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs deleted file mode 100644 index 41eb054..0000000 --- a/nearby/presence/np_adv/src/extended/deserialize/parse_tests.rs +++ /dev/null
@@ -1,703 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; -use super::*; -use crate::extended::deserialize::encrypted_section::{ - MicEncryptedSection, SignatureEncryptedSection, -}; -use crate::extended::deserialize::test_stubs::IntermediateSectionExt; -use rand::rngs::StdRng; -use rand::seq::SliceRandom; -use rand::{Rng, SeedableRng}; -use std::vec; - -#[test] -fn parse_adv_ext_public_identity() { - // 2 sections, 3 DEs each - let mut adv_body = vec![]; - // section - adv_body.push(10); - // public identity - adv_body.push(0x03); - // de 1 byte header, type 5, len 5 - adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); - // de 2 byte header, type 6, len 1 - adv_body.extend_from_slice(&[0x81, 0x06, 0x01]); - - let parsed_sections = - parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap().into_vec(); - assert_eq!( - vec![IntermediateSection::from(PlaintextSection::new( - PlaintextIdentityMode::Public, - SectionContents::new(10, &adv_body[2..], 1) - ))], - parsed_sections, - ); - let expected_des = [ - // 1 byte header, len 5 - DataElement { - offset: 1_u8.into(), - de_type: 5_u8.into(), - contents: &[0x01, 0x02, 0x03, 0x04, 0x05], - }, - // 2 byte header, len 1 - DataElement { offset: 2_u8.into(), de_type: 6_u8.into(), contents: &[0x01] }, - ]; - - assert_eq!( - &expected_des[..], - &parsed_sections[0].as_plaintext().unwrap().collect_data_elements().unwrap() - ); -} - -#[test] -fn parse_adv_ext_identity() { - // 3 sections - let mut adv_body = vec![]; - // section - 48 bytes total - adv_body.push(19 + 18 + 10); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x08, // scheme (signature) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // private identity -- 2 + 16x 0x33 - adv_body.extend_from_slice(&[ - 0x90, 0x01, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, - ]); - // 10 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 10]); - - // section - 49 bytes total - adv_body.push(19 + 18 + 11); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x08, // scheme (signature) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // trusted identity -- 2 + 16x 0x55 - adv_body.extend_from_slice(&[ - 0x90, 0x02, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, - ]); - // 11 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 11]); - - // section - 50 bytes total - adv_body.push(19 + 18 + 12); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x08, // scheme (signature) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // provisioned identity -- 2 + 16x 0x77 - adv_body.extend_from_slice(&[ - 0x90, 0x04, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x77, - ]); - // 12 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 12]); - - let adv_header = V1Header { header_byte: 0x20 }; - let encryption_info = EncryptionInfo { - bytes: [ - 0x91, 0x10, // header bytes - 0x08, // scheme (signature) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, - ], - }; - let expected_sections = [ - SignatureEncryptedSection { - contents: EncryptedSectionContents { - section_header: 47, - adv_header, - encryption_info: encryption_info.clone(), - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x01], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Private, - }, - // skip section header + encryption info + identity header -> end of section - all_ciphertext: &adv_body[1 + 19 + 2..48], - }, - }, - SignatureEncryptedSection { - contents: EncryptedSectionContents { - section_header: 48, - adv_header, - encryption_info: encryption_info.clone(), - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x02], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Trusted, - }, - all_ciphertext: &adv_body[48 + 1 + 19 + 2..97], - }, - }, - SignatureEncryptedSection { - contents: EncryptedSectionContents { - section_header: 49, - adv_header, - encryption_info, - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x04], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Provisioned, - }, - all_ciphertext: &adv_body[97 + 1 + 19 + 2..], - }, - }, - ]; - let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); - assert_eq!(parsed_sections.into_vec(), expected_sections.map(IntermediateSection::from)); -} - -#[test] -fn parse_adv_ext_mic_identity() { - // 3 sections - let mut adv_body = vec![]; - // section - 64 bytes total - adv_body.push(19 + 18 + 10 + 16); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x00, // scheme (mic) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // private identity -- 2 + 16x 0x55 - adv_body.extend_from_slice(&[ - 0x90, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, - ]); - // 10 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 10]); - // mic - 16x 0x33 - adv_body.extend_from_slice(&[ - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, - ]); - - // section - 65 bytes total - adv_body.push(19 + 18 + 11 + 16); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x00, // scheme (mic) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // trusted identity -- 2 + 16x 0x77 - adv_body.extend_from_slice(&[ - 0x90, 0x02, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, - 0x77, 0x77, 0x77, - ]); - // 11 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 11]); - // mic - 16x 0x66 - adv_body.extend_from_slice(&[ - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, - ]); - - // section - 66 bytes total - adv_body.push(19 + 18 + 12 + 16); - // encryption info -- 2 + 1 + 16x 0x11 - adv_body.extend_from_slice(&[ - 0x91, 0x10, // header - 0x00, // scheme (mic) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, // salt - ]); - // provisioned identity -- 2 + 16x 0xAA - adv_body.extend_from_slice(&[ - 0x90, 0x04, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, - ]); - // 12 bytes of 0xFF ciphertext - adv_body.extend_from_slice(&[0xFF; 12]); - // mic - 16x 0x99 - adv_body.extend_from_slice(&[ - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, - ]); - - let adv_header = V1Header { header_byte: 0x20 }; - let encryption_info = EncryptionInfo { - bytes: [ - 0x91, 0x10, // header bytes - 0x00, // scheme (mic) - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, - ], - }; - let expected_sections = [ - MicEncryptedSection { - contents: EncryptedSectionContents { - section_header: 63, - adv_header, - encryption_info: encryption_info.clone(), - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x01], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Private, - }, - // skip section header + encryption info + identity header -> end of ciphertext - all_ciphertext: &adv_body[1 + 19 + 2..64 - 16], - }, - mic: SectionMic::from([0x33; 16]), - }, - MicEncryptedSection { - contents: EncryptedSectionContents { - section_header: 64, - adv_header, - encryption_info: encryption_info.clone(), - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x02], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Trusted, - }, - all_ciphertext: &adv_body[64 + 1 + 19 + 2..129 - 16], - }, - mic: SectionMic::from([0x66; 16]), - }, - MicEncryptedSection { - contents: EncryptedSectionContents { - section_header: 65, - adv_header, - encryption_info, - identity: EncryptedIdentityMetadata { - header_bytes: [0x90, 0x04], - offset: 1_u8.into(), - identity_type: EncryptedIdentityDataElementType::Provisioned, - }, - all_ciphertext: &adv_body[129 + 1 + 19 + 2..195 - 16], - }, - mic: SectionMic::from([0x99; 16]), - }, - ]; - let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); - assert_eq!(parsed_sections.into_vec(), &expected_sections.map(IntermediateSection::from)); -} - -#[test] -fn parse_de_with_1_byte_header() { - let data = [0x51, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[6..], - ProtoDataElement { - header: DeHeader { - de_type: 1_u8.into(), - header_bytes: ArrayView::try_from_slice(&[0x51]).unwrap(), - contents_len: 5_u8.try_into().unwrap() - }, - contents: &data[1..6] - } - )), - ProtoDataElement::parse(&data) - ); -} - -#[test] -fn parse_de_with_2_byte_header() { - let data = [0x85, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[7..], - ProtoDataElement { - header: DeHeader { - de_type: 1_u8.into(), - header_bytes: ArrayView::try_from_slice(&[0x85, 0x01]).unwrap(), - contents_len: 5_u8.try_into().unwrap() - }, - contents: &data[2..7] - } - )), - ProtoDataElement::parse(&data) - ); -} - -#[test] -fn parse_de_with_3_byte_header() { - let data = [0x85, 0xC1, 0x41, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[8..], - ProtoDataElement { - header: DeHeader { - header_bytes: ArrayView::try_from_slice(&[0x85, 0xC1, 0x41]).unwrap(), - contents_len: 5_u8.try_into().unwrap(), - de_type: 0b0000_0000_0000_0000_0010_0000_1100_0001_u32.into(), - }, - contents: &data[3..8] - } - )), - ProtoDataElement::parse(&data) - ); -} - -#[test] -fn parse_de_header_1_byte() { - let data = [0x51, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[1..], - DeHeader { - de_type: 1_u8.into(), - contents_len: 5_u8.try_into().unwrap(), - header_bytes: ArrayView::try_from_slice(&[0x51]).unwrap(), - } - )), - DeHeader::parse(&data) - ); -} - -#[test] -fn parse_de_header_2_bytes() { - let data = [0x83, 0x01, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[2..], - DeHeader { - de_type: 1_u8.into(), - contents_len: 3_u8.try_into().unwrap(), - header_bytes: ArrayView::try_from_slice(&[0x83, 0x01]).unwrap(), - } - )), - DeHeader::parse(&data) - ); -} - -#[test] -fn parse_de_header_3_bytes() { - let data = [0x83, 0xC1, 0x41, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[3..], - DeHeader { - de_type: 0b0000_0000_0000_0000_0010_0000_1100_0001_u32.into(), - contents_len: 3_u8.try_into().unwrap(), - header_bytes: ArrayView::try_from_slice(&[0x83, 0xC1, 0x41]).unwrap(), - } - )), - DeHeader::parse(&data) - ); -} - -#[test] -fn parse_de_header_4_bytes() { - let data = [0x83, 0xC1, 0xC1, 0x41, 0xFF, 0xFF]; - assert_eq!( - Ok(( - &data[4..], - DeHeader { - de_type: 0b0000_0000_0001_0000_0110_0000_1100_0001_u32.into(), - contents_len: 3_u8.try_into().unwrap(), - header_bytes: ArrayView::try_from_slice(&[0x83, 0xC1, 0xC1, 0x41]).unwrap(), - } - )), - DeHeader::parse(&data) - ); -} - -#[test] -fn public_identity_not_first_de_error() { - let mut adv_body = vec![]; - // section - adv_body.push(3 + 1); - // misc other DE - adv_body.extend_from_slice(&[0x81, 0x70, 0xFF]); - // public identity after another DE - adv_body.push(0x03); - - assert_eq!( - nom::Err::Error(error::Error { input: &adv_body[1..], code: error::ErrorKind::Verify }), - parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap_err() - ); -} - -#[test] -fn invalid_public_section() { - let mut rng = StdRng::from_entropy(); - for _ in 0..100 { - let mut adv_body = vec![]; - // Add section length - let remove_section_len = rng.gen_bool(0.5); - // Add public identity - let add_public_identity = rng.gen_bool(0.5); - // Add DEs - let add_des = rng.gen_bool(0.5); - // Shuffle adv - let shuffle = rng.gen_bool(0.5); - - adv_body.push(0); - if add_public_identity { - adv_body[0] += 1; - adv_body.push(0x03); - } - if add_des { - adv_body[0] += 1; - adv_body.extend_from_slice(&[0x81]); - } - if remove_section_len { - let _ = adv_body.remove(0); - } - - let ordered_adv = adv_body.clone(); - - if shuffle { - adv_body.shuffle(&mut rng); - } - // A V1 public section is invalid if - // * section length is missing - // * the section is empty - // * the section identity is missing - // * the identity does not follow the section length - // * the section length is 0 - if remove_section_len || !add_public_identity || (ordered_adv != adv_body) { - let _ = parse_sections(V1Header { header_byte: 0x20 }, &adv_body) - .expect_err("Expected to fail because of missing section length or identity"); - } - } -} - -// There can only be one identity DE -#[test] -fn public_identity_after_public_identity_error() { - let mut adv_body = vec![]; - // section - adv_body.push(1 + 3 + 1); - // public identity after another DE - adv_body.push(0x03); - // misc other DE - adv_body.extend_from_slice(&[0x81, 0x70, 0xFF]); - // public identity after another DE - adv_body.push(0x03); - - let sections = parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap(); - assert_eq!(sections.len(), 1); - assert_eq!( - DataElementParseError::DuplicateIdentityDataElement, - sections[0].as_plaintext().unwrap().collect_data_elements().unwrap_err() - ); -} - -#[test] -fn salt_public_identity_error() { - let mut adv_body = vec![]; - // section - adv_body.push(3 + 1 + 3); - // salt - 1 + 2x 0x22 (invalid: must be first DE) - adv_body.extend_from_slice(&[0x20, 0x22, 0x22]); - // public identity - adv_body.push(0x03); - // misc other DE - adv_body.extend_from_slice(&[0x81, 0x70, 0xFF]); - - assert_eq!( - nom::Err::Error(error::Error { - input: &adv_body[1..], - // Eof because all_consuming is used to ensure complete section is parsed - code: error::ErrorKind::Verify - }), - parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap_err() - ); -} - -#[test] -fn salt_mic_public_identity_error() { - let mut adv_body = vec![]; - // section - adv_body.push(3 + 18 + 1 + 3); - // salt - 1 + 2x 0x22 (invalid: must be first DE) - adv_body.extend_from_slice(&[0x20, 0x22, 0x22]); - // mic - 2 + 16x 0x33 - adv_body.extend_from_slice(&[ - 0x90, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, - ]); - // public identity - adv_body.push(0x03); - // misc other DE - adv_body.extend_from_slice(&[0x81, 0x70, 0xFF]); - - assert_eq!( - nom::Err::Error(error::Error { - input: &adv_body[1..], - // Eof because all_consuming is used to ensure complete section is parsed - code: error::ErrorKind::Verify - }), - parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap_err() - ); -} - -#[test] -fn parse_adv_no_identity() { - let adv_body = vec![0x55, 0x01, 0x02, 0x03, 0x04, 0x05]; - assert_eq!( - nom::Err::Error(error::Error { input: &adv_body[1..], code: error::ErrorKind::Eof }), - parse_sections(V1Header { header_byte: 0x20 }, &adv_body).unwrap_err() - ); -} - -#[test] -fn parse_empty_section() { - // empty section - should return an EOF error - let input = []; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read section contents - input: input.as_slice(), - code: error::ErrorKind::Eof - }), - IntermediateSection::parser_encrypted_with_header(V1Header { header_byte: 0x20 })(&input) - .unwrap_err() - ); -} - -#[test] -fn parse_de_header_non_canonical_multi_byte() { - // length 1, type 1 - // first byte of type doesn't have any bits in it so it contributes nothing - let input = [0b1000_0001, 0b1000_0000, 0b0000_0001]; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read first type byte - input: &input.as_slice()[1..], - code: error::ErrorKind::Verify - }), - DeHeader::parse(&input).unwrap_err() - ); -} - -#[test] -fn parse_section_length_zero() { - // Section length of 0 - should return a verification error - let input = [0x00]; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read section contents - input: input.as_slice(), - code: error::ErrorKind::Verify - }), - IntermediateSection::parser_encrypted_with_header(V1Header { header_byte: 0x20 })(&input) - .unwrap_err() - ); -} - -#[test] -fn parse_section_length_overrun() { - // section of length 0xF0 - legal but way longer than 3 - let input = [0xF0, 0x01, 0x02, 0x03]; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read section contents - input: &input.as_slice()[1..], - code: error::ErrorKind::Eof - }), - IntermediateSection::parser_encrypted_with_header(V1Header { header_byte: 0x20 })(&input) - .unwrap_err() - ); -} - -#[test] -fn parse_de_single_byte_header_length_overrun() { - // length 7, type 0x03 - let input = [0b0111_0011, 0x01, 0x02]; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read DE contents - input: &input.as_slice()[1..], - code: error::ErrorKind::Eof - }), - ProtoDataElement::parse(&input).unwrap_err() - ); -} - -#[test] -fn parse_de_multi_byte_header_length_overrun() { - // length 7, type 0x0F - let input = [0b1000_0111, 0x0F, 0x01, 0x02]; - assert_eq!( - nom::Err::Error(error::Error { - // attempted to read DE contents - input: &input.as_slice()[2..], - code: error::ErrorKind::Eof - }), - ProtoDataElement::parse(&input).unwrap_err() - ); -} - -#[test] -fn parse_adv_signature_encrypted_plaintext_mix() { - // 2 sections - let mut adv_body = vec![]; - - // section 1 - plaintext - 10 bytes - adv_body.push(10); - // public identity - adv_body.push(0x03); - // de 1 byte header, type 5, len 5 - adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); - // de 2 byte header, type 6, len 1 - adv_body.extend_from_slice(&[0x81, 0x06, 0x01]); - - // section 2 - plaintext - 10 bytes - adv_body.push(10); - // public identity - adv_body.push(0x03); - // de 1 byte header, type 5, len 5 - adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); - // de 2 byte header, type 6, len 1 - adv_body.extend_from_slice(&[0x81, 0x06, 0x01]); - - let adv_header = V1Header { header_byte: 0x20 }; - - assert_eq!( - nom::Err::Error(error::Error { input: &adv_body[11..], code: error::ErrorKind::Eof }), - parse_sections(adv_header, &adv_body).unwrap_err() - ); -} - -// for convenient .into() in expected test data - -impl<'a> From<SignatureEncryptedSection<'a>> for IntermediateSection<'a> { - fn from(s: SignatureEncryptedSection<'a>) -> Self { - IntermediateSection::Ciphertext(CiphertextSection::SignatureEncryptedIdentity(s)) - } -} - -impl<'a> From<MicEncryptedSection<'a>> for IntermediateSection<'a> { - fn from(s: MicEncryptedSection<'a>) -> Self { - IntermediateSection::Ciphertext(CiphertextSection::MicEncryptedIdentity(s)) - } -} - -impl<'a> From<PlaintextSection<'a>> for IntermediateSection<'a> { - fn from(s: PlaintextSection<'a>) -> Self { - IntermediateSection::Plaintext(s) - } -}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section/header/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/section/header/mod.rs new file mode 100644 index 0000000..cb6a955 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/section/header/mod.rs
@@ -0,0 +1,141 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! High-level, early-stage parsed structures for a section: the header, then everything else. + +use crate::extended::{ + deserialize, salt::ShortV1Salt, V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, V1_ENCODING_UNENCRYPTED, + V1_IDENTITY_TOKEN_LEN, +}; +use crate::helpers::parse_byte_array; +use nom::{combinator, error, number, sequence}; +use np_hkdf::v1_salt::{ExtendedV1Salt, EXTENDED_SALT_LEN}; + +#[cfg(test)] +mod tests; + +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum SectionHeader { + Unencrypted, + Encrypted(EncryptedSectionHeader), +} + +impl SectionHeader { + /// Returns the parsed header and the remaining length of the section contents + /// + /// This structure makes it easy to get a slice of the entire header with + /// [combinator::consumed] for later inclusion in signatures etc, but also + /// to [nom::bytes::complete::take] the rest of the section with a minimum of + /// error-prone length calculations. + pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], (&[u8], Self, u8)> { + // Consume first 1-2 bytes of format + // 0bERRRSSSS first header byte + let (input, (format_bytes, (first_header_byte, maybe_second_byte))) = + combinator::consumed(nom::branch::alt(( + // Extended bit not set, verify all reserved bits are 0 + combinator::map( + combinator::verify(number::complete::u8, |b| { + !deserialize::hi_bit_set(*b) && (*b & 0x70) == 0 + }), + |b| (b, None), + ), + // Extended bit is set, take another byte and verify all reserved bits are 0 + combinator::map( + nom::sequence::pair( + combinator::verify(number::complete::u8, |b| { + deserialize::hi_bit_set(*b) && (*b & 0x70) == 0 + }), + combinator::verify(number::complete::u8, |second_byte| *second_byte == 0u8), + ), + |(b1, b2)| (b1, Some(b2)), + ), + )))(input)?; + + let encoding = first_header_byte & 0x0F; + + let (input, section_header) = match (encoding, maybe_second_byte) { + (V1_ENCODING_UNENCRYPTED, None) => Ok((input, (SectionHeader::Unencrypted))), + (V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN, None) => combinator::map( + sequence::tuple((ShortV1Salt::parse, CiphertextExtendedIdentityToken::parse)), + |(salt, token)| { + SectionHeader::Encrypted(EncryptedSectionHeader::MicShortSalt { salt, token }) + }, + )(input), + (V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, None) => combinator::map( + sequence::tuple((parse_v1_extended_salt, CiphertextExtendedIdentityToken::parse)), + |(salt, token)| { + SectionHeader::Encrypted(EncryptedSectionHeader::MicExtendedSalt { + salt, + token, + }) + }, + )(input), + (V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, None) => { + combinator::map( + sequence::tuple(( + parse_v1_extended_salt, + CiphertextExtendedIdentityToken::parse, + )), + |(salt, token)| { + SectionHeader::Encrypted(EncryptedSectionHeader::SigExtendedSalt { + salt, + token, + }) + }, + )(input) + } + _ => Err(nom::Err::Error(error::Error::new(input, error::ErrorKind::Alt))), + }?; + + //finally parse the section payload length, this is the same regardless of encoding scheme + let (input, section_len) = combinator::verify(number::complete::u8, |b| { + // length cannot be 0 for an unencrypted section as this is meaningless + !(encoding == V1_ENCODING_UNENCRYPTED && *b == 0u8) + })(input)?; + + Ok((input, (format_bytes, section_header, section_len))) + } +} + +fn parse_v1_extended_salt(input: &[u8]) -> nom::IResult<&[u8], ExtendedV1Salt> { + combinator::map(parse_byte_array::<{ EXTENDED_SALT_LEN }>, ExtendedV1Salt::from)(input) +} + +#[allow(clippy::enum_variant_names)] +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum EncryptedSectionHeader { + MicShortSalt { salt: ShortV1Salt, token: CiphertextExtendedIdentityToken }, + MicExtendedSalt { salt: ExtendedV1Salt, token: CiphertextExtendedIdentityToken }, + SigExtendedSalt { salt: ExtendedV1Salt, token: CiphertextExtendedIdentityToken }, +} + +/// 16-byte identity token, straight out of the section. +/// +/// If identity resolution succeeds, decrypted to an [ExtendedIdentityToken](crate::extended::V1IdentityToken). +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) struct CiphertextExtendedIdentityToken(pub(crate) [u8; V1_IDENTITY_TOKEN_LEN]); + +impl CiphertextExtendedIdentityToken { + pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], Self> { + combinator::map(parse_byte_array::<V1_IDENTITY_TOKEN_LEN>, Self)(input) + } +} + +impl From<[u8; V1_IDENTITY_TOKEN_LEN]> for CiphertextExtendedIdentityToken { + fn from(value: [u8; V1_IDENTITY_TOKEN_LEN]) -> Self { + Self(value) + } +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section/header/tests.rs b/nearby/presence/np_adv/src/extended/deserialize/section/header/tests.rs new file mode 100644 index 0000000..92cd5da --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/section/header/tests.rs
@@ -0,0 +1,194 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod happy_path { + use super::super::*; + use alloc::vec; + + #[test] + fn parse_extended_bit_not_set() { + assert_eq!( + SectionHeader::parse(&[0b0000_0000, 3]).expect("Parsing should succeed"), + ([].as_slice(), (&[0u8][..], SectionHeader::Unencrypted, 3u8)) + ); + } + + #[test] + fn parse_with_extended_bit_set() { + let _ = SectionHeader::parse(&[0b1000_0000, 0b0000_0000, 4]) + .expect_err("Extended bits should not be parsed at this time"); + } + + #[test] + fn parse_section_header_mic_with_short_salt() { + let mut section_header = vec![]; + section_header.push(0b0000_0001u8); //format + section_header.extend_from_slice(&[0xFF; 2]); // short salt + section_header.extend_from_slice(&[0xCC; 16]); // identity token + section_header.push(100); // payload length + + assert_eq!( + SectionHeader::parse(section_header.as_slice()).expect("Parsing should succeed"), + ( + [].as_slice(), + ( + &[0b0000_0001u8][..], + SectionHeader::Encrypted(EncryptedSectionHeader::MicShortSalt { + salt: [0xFF; 2].into(), + token: [0xCC; 16].into(), + }), + 100 + ) + ) + ); + } + + #[test] + fn parse_section_header_multi_byte_mic_with_short_salt() { + let mut section_header = vec![]; + section_header.extend_from_slice(&[0b1000_0001u8, 0b0000_0000]); //format + section_header.extend_from_slice(&[0xFF; 2]); // short salt + section_header.extend_from_slice(&[0xCC; 16]); // identity token + section_header.push(100); // payload length + let _ = SectionHeader::parse(section_header.as_slice()) + .expect_err("Extended bit parsing should fail at this time"); + } + + #[test] + fn parse_section_header_mic_with_extended_salt() { + let mut section_header = vec![]; + section_header.push(0b0000_0010u8); //format + section_header.extend_from_slice(&[0xFF; 16]); // short salt + section_header.extend_from_slice(&[0xCC; 16]); // identity token + section_header.push(100); // payload length + + assert_eq!( + SectionHeader::parse(section_header.as_slice()).expect("Parsing should succeed"), + ( + [].as_slice(), + ( + &[0b0000_0010u8][..], + SectionHeader::Encrypted(EncryptedSectionHeader::MicExtendedSalt { + salt: [0xFF; 16].into(), + token: [0xCC; 16].into(), + }), + 100 + ) + ) + ); + } + + #[test] + fn parse_section_header_sig_with_extended_salt() { + let mut section_header = vec![]; + section_header.push(0b0000_0011u8); //format + section_header.extend_from_slice(&[0xFF; 16]); // short salt + section_header.extend_from_slice(&[0xCC; 16]); // identity token + section_header.push(100); // payload length + + assert_eq!( + SectionHeader::parse(section_header.as_slice()).expect("Parsing should succeed"), + ( + [].as_slice(), + ( + &[0b0000_0011u8][..], + SectionHeader::Encrypted(EncryptedSectionHeader::SigExtendedSalt { + salt: [0xFF; 16].into(), + token: [0xCC; 16].into(), + }), + 100 + ) + ) + ); + } +} + +mod error_condition { + use super::super::*; + use alloc::vec; + + #[test] + fn parse_single_byte_invalid_reserve() { + let _ = SectionHeader::parse(&[0b0001_0000, 3]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b0011_0000, 3]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b0111_0000, 3]) + .expect_err("Invalid reserve bits should fail to parse"); + } + + #[test] + fn parse_multi_byte_invalid_reserve_bits() { + let _ = SectionHeader::parse(&[0b1000_0000, 0b1000_0000, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1000_0000, 0b1111_1111, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1000_0000, 0b0000_0001, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1000_0000, 0b0001_0000, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1001_0000, 0b0000_0000, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1100_0000, 0b0000_0000, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + let _ = SectionHeader::parse(&[0b1100_0000, 0b0000_0001, 4]) + .expect_err("Invalid reserve bits should fail to parse"); + } + + #[test] + fn parse_section_header_unencrypted_encoding_zero_length_payload() { + let _ = SectionHeader::parse(&[0b0000_0000, 0]) + .expect_err("0 is an invalid section length for unencrypted sections"); + } + + #[test] + fn parse_section_header_mic_with_short_salt_too_short() { + let _ = SectionHeader::parse(&[0b0000_0001]) + .expect_err("Not enough bytes present to parse a mic with short salt"); + } + + #[test] + fn parse_section_header_mic_with_short_salt_missing_length() { + let mut section_header = vec![]; + section_header.push(0b0000_0001u8); //format + section_header.extend_from_slice(&[0xFF; 2]); // short salt + section_header.extend_from_slice(&[0xCC; 16]); // identity token + + let _ = SectionHeader::parse(section_header.as_slice()) + .expect_err("Section payload length byte is missing"); + } +} + +mod coverage_gaming { + use crate::extended::deserialize::section::header::{ + CiphertextExtendedIdentityToken, EncryptedSectionHeader, + }; + use alloc::format; + + #[test] + fn ct_identity_token_clone() { + let token = CiphertextExtendedIdentityToken([0; 16]); + #[allow(clippy::clone_on_copy)] + let _ = token.clone(); + } + + #[test] + fn encrypted_section_header_debug() { + let header = EncryptedSectionHeader::MicShortSalt { + salt: [0; 2].into(), + token: CiphertextExtendedIdentityToken([0; 16]), + }; + let _ = format!("{:?}", header); + } +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/mod.rs b/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/mod.rs new file mode 100644 index 0000000..f998299 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/mod.rs
@@ -0,0 +1,289 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Covers the first half of section parsing before decryption, if relevant, is +//! attempted. + +use crate::{ + array_vec::ArrayVecOption, + extended::{ + deserialize::{ + encrypted_section::{ + EncryptedSectionContents, MicEncryptedSection, SectionIdentityResolutionContents, + SignatureEncryptedSection, + }, + section::header::{ + CiphertextExtendedIdentityToken, EncryptedSectionHeader, SectionHeader, + }, + DataElementParsingIterator, Section, SectionMic, + }, + salt::MultiSalt, + NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, + }, + header::V1AdvHeader, +}; +use crypto_provider::CryptoProvider; +use nom::{branch, bytes, combinator, error, multi}; + +use crate::extended::deserialize::data_element::DataElementParseError; +#[cfg(feature = "devtools")] +use crate::{ + credential::v1::V1DiscoveryCryptoMaterial, deserialization_arena::DeserializationArenaAllocator, +}; +#[cfg(feature = "devtools")] +use crate::{deserialization_arena::ArenaOutOfSpace, extended::NP_ADV_MAX_SECTION_LEN}; +#[cfg(feature = "devtools")] +use array_view::ArrayView; + +#[cfg(test)] +pub(crate) mod tests; + +/// Parse into [IntermediateSection]s, exposing the underlying parsing errors. +/// Consumes all of `adv_body`. +pub(crate) fn parse_sections( + adv_header: V1AdvHeader, + adv_body: &[u8], +) -> Result< + ArrayVecOption<IntermediateSection, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT>, + nom::Err<error::Error<&[u8]>>, +> { + combinator::all_consuming(branch::alt(( + // Public advertisement + multi::fold_many_m_n( + 1, + NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, + IntermediateSection::parser_unencrypted_section, + ArrayVecOption::default, + |mut acc, item| { + acc.push(item); + acc + }, + ), + // Encrypted advertisement + multi::fold_many_m_n( + 1, + NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, + IntermediateSection::parser_encrypted_with_header(adv_header), + ArrayVecOption::default, + |mut acc, item| { + acc.push(item); + acc + }, + ), + )))(adv_body) + .map(|(_rem, sections)| sections) +} + +/// A partially processed section that hasn't been decrypted (if applicable) yet. +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum IntermediateSection<'a> { + /// A section that was not encrypted, e.g. a public identity or no-identity section. + Plaintext(PlaintextSection<'a>), + /// A section whose contents were encrypted, e.g. a private identity section. + Ciphertext(CiphertextSection<'a>), +} + +impl<'a> IntermediateSection<'a> { + fn parser_unencrypted_section( + np_adv_body: &'a [u8], + ) -> nom::IResult<&'a [u8], IntermediateSection<'a>> { + combinator::map_opt(SectionContents::parse, |sc| match sc.header { + SectionHeader::Unencrypted => { + Some(IntermediateSection::Plaintext(PlaintextSection::new(sc.contents))) + } + SectionHeader::Encrypted(_) => None, + })(np_adv_body) + } + + pub(crate) fn parser_encrypted_with_header( + adv_header: V1AdvHeader, + ) -> impl Fn(&'a [u8]) -> nom::IResult<&[u8], IntermediateSection> { + move |adv_body| { + fn split_at_mic(contents: &[u8]) -> Option<(&[u8], SectionMic)> { + contents.len().checked_sub(SectionMic::CONTENTS_LEN).map(|len_before_mic| { + let (before_mic, mic) = contents.split_at(len_before_mic); + let mic = SectionMic::try_from(mic).expect("MIC length checked above"); + + (before_mic, mic) + }) + } + + fn build_mic_section<'a>( + adv_header: V1AdvHeader, + format_bytes: &'a [u8], + salt: MultiSalt, + token: CiphertextExtendedIdentityToken, + contents_len: u8, + contents: &'a [u8], + ) -> Option<IntermediateSection<'a>> { + split_at_mic(contents).map(|(before_mic, mic)| { + IntermediateSection::Ciphertext(CiphertextSection::MicEncrypted( + MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + format_bytes, + salt, + token, + contents_len, + before_mic, + ), + mic, + }, + )) + }) + } + + combinator::map_opt( + combinator::map_opt(SectionContents::parse, |sc| match sc.header { + SectionHeader::Unencrypted => None, + SectionHeader::Encrypted(e) => { + Some((sc.format_bytes, sc.contents, sc.contents_len, e)) + } + }), + move |(format_bytes, contents, contents_len, header)| match header { + EncryptedSectionHeader::MicShortSalt { salt, token } => build_mic_section( + adv_header, + format_bytes, + salt.into(), + token, + contents_len, + contents, + ), + EncryptedSectionHeader::MicExtendedSalt { salt, token } => build_mic_section( + adv_header, + format_bytes, + salt.into(), + token, + contents_len, + contents, + ), + EncryptedSectionHeader::SigExtendedSalt { salt, token } => { + Some(IntermediateSection::Ciphertext( + CiphertextSection::SignatureEncrypted(SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + format_bytes, + salt, + token, + contents_len, + contents, + ), + }), + )) + } + }, + )(adv_body) + } + } +} + +/// Components of a section after header decode, but before decryption or DE parsing. +/// +/// This is just the first stage of parsing sections, followed by [IntermediateSection]. +#[derive(PartialEq, Eq, Debug)] +pub(crate) struct SectionContents<'adv> { + /// 1-2 bytes of the format saved for later use in verification + pub(crate) format_bytes: &'adv [u8], + /// Section header contents which includes salt + identity token + pub(crate) header: SectionHeader, + /// Contents of the section after the header. + /// No validation is performed on the contents. + pub(crate) contents: &'adv [u8], + /// The length of the contents stored as an u8. + pub(crate) contents_len: u8, +} + +impl<'adv> SectionContents<'adv> { + pub(crate) fn parse(input: &'adv [u8]) -> nom::IResult<&'adv [u8], Self> { + let (input, (format_bytes, header, contents_len)) = SectionHeader::parse(input)?; + let (input, contents) = bytes::complete::take(contents_len)(input)?; + + Ok((input, Self { format_bytes, header, contents, contents_len })) + } +} + +/// A plaintext section deserialized from a V1 advertisement. +#[derive(PartialEq, Eq, Debug)] +pub struct PlaintextSection<'adv> { + contents: &'adv [u8], +} + +impl<'adv> PlaintextSection<'adv> { + pub(crate) fn new(contents: &'adv [u8]) -> Self { + Self { contents } + } +} + +impl<'adv> Section<'adv, DataElementParseError> for PlaintextSection<'adv> { + type Iterator = DataElementParsingIterator<'adv>; + + fn iter_data_elements(&self) -> Self::Iterator { + DataElementParsingIterator::new(self.contents) + } +} + +#[derive(PartialEq, Eq, Debug)] +pub(crate) enum CiphertextSection<'a> { + SignatureEncrypted(SignatureEncryptedSection<'a>), + MicEncrypted(MicEncryptedSection<'a>), +} + +impl<'a> CiphertextSection<'a> { + /// Try decrypting into some raw bytes given some raw unsigned crypto-material. + #[cfg(feature = "devtools")] + pub(crate) fn try_resolve_identity_and_decrypt< + C: V1DiscoveryCryptoMaterial, + P: CryptoProvider, + >( + &self, + allocator: &mut DeserializationArenaAllocator<'a>, + crypto_material: &C, + ) -> Option<Result<ArrayView<u8, { NP_ADV_MAX_SECTION_LEN }>, ArenaOutOfSpace>> { + match self { + CiphertextSection::SignatureEncrypted(x) => { + let identity_resolution_material = + crypto_material.signed_identity_resolution_material::<P>(); + x.try_resolve_identity_and_decrypt::<P>(allocator, &identity_resolution_material) + } + CiphertextSection::MicEncrypted(x) => match x.contents.salt { + MultiSalt::Short(_) => x.try_resolve_short_salt_identity_and_decrypt::<P>( + allocator, + &crypto_material.mic_short_salt_identity_resolution_material::<P>(), + ), + MultiSalt::Extended(_) => x.try_resolve_extended_salt_identity_and_decrypt::<P>( + allocator, + &crypto_material.mic_extended_salt_identity_resolution_material::<P>(), + ), + }, + } + } + + /// Return the data needed to resolve identities. + /// + /// In the typical case of trying many identities across a few sections, + /// these should be calculated once for all relevant sections, then re-used + /// for all identity match attempts. + pub(crate) fn identity_resolution_contents<C: CryptoProvider>( + &self, + ) -> SectionIdentityResolutionContents { + match self { + CiphertextSection::SignatureEncrypted(x) => { + x.contents.compute_identity_resolution_contents::<C>() + } + CiphertextSection::MicEncrypted(x) => { + x.contents.compute_identity_resolution_contents::<C>() + } + } + } +}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/tests.rs b/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/tests.rs new file mode 100644 index 0000000..84ce763 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/section/intermediate/tests.rs
@@ -0,0 +1,725 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +//! Tests for intermediate sections representation and logic - this is the initial stage of parsing +//! before any ciphertext is actually decrypted. + +extern crate std; +use std::{prelude::rust_2021::*, vec}; + +use super::*; +use crate::{ + extended::{ + deserialize::{ + data_element::DataElement, + encrypted_section::{ + EncryptedSectionContents, MicEncryptedSection, SignatureEncryptedSection, + }, + SectionMic, + }, + salt::{ShortV1Salt, SHORT_SALT_LEN}, + serialize::{AdvBuilder, AdvertisementType}, + NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, V1_ENCODING_UNENCRYPTED, + V1_IDENTITY_TOKEN_LEN, + }, + header::V1AdvHeader, + NpVersionHeader, +}; +use crypto_provider_default::CryptoProviderImpl; +use nom::error; +use np_hkdf::v1_salt::EXTENDED_SALT_LEN; +use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng as _}; + +/// Section header length after the length byte for ext salt + token +const EXT_SALT_SECTION_HEADER_LEN: usize = 1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1; + +/// Section header length after the length byte for ext salt + token +const SHORT_SALT_SECTION_HEADER_LEN: usize = 1 + SHORT_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1; + +mod happy_path { + use super::*; + use crate::{ + extended::{data_elements::TxPowerDataElement, serialize::UnencryptedSectionEncoder}, + shared_data::TxPower, + }; + use np_hkdf::v1_salt::ExtendedV1Salt; + + #[test] + fn parse_adv_ext_public_identity() { + let mut adv_body = vec![]; + // public identity + adv_body.push(V1_ENCODING_UNENCRYPTED); + // section len + adv_body.push(6 + 3); + // de 1 byte header, type 5, len 5 + adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 22, len 1 + adv_body.extend_from_slice(&[0x81, 0x16, 0x01]); + + let parsed_sections = parse_sections(V1AdvHeader::new(0x20), &adv_body).unwrap().into_vec(); + assert_eq!( + vec![IntermediateSection::from(PlaintextSection::new(&adv_body[2..]))], + parsed_sections, + ); + let expected_des = [ + // 1 byte header, len 5 + DataElement::new(0_u8.into(), 5_u8.into(), &[0x01, 0x02, 0x03, 0x04, 0x05]), + // 2 byte header, len 1 + DataElement::new(1_u8.into(), 22_u8.into(), &[0x01]), + ]; + + assert_eq!( + &expected_des[..], + &parsed_sections[0].as_plaintext().unwrap().collect_data_elements().unwrap() + ); + } + + #[test] + fn do_deserialize_max_number_of_public_sections() { + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + for _ in 0..NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT { + let mut section_builder = + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); + section_builder + .add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(7).unwrap())) + .unwrap(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + } + + let adv = adv_builder.into_advertisement(); + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + let sections = parse_sections(v1_header, remaining).unwrap(); + assert_eq!(NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, sections.len()); + } + + #[test] + fn max_number_encrypted_sections_mic() { + let mut adv_body = vec![]; + for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT { + let _ = add_mic_short_salt_section_to_adv(&mut adv_body); + } + let adv_header = V1AdvHeader::new(0x20); + assert!(parse_sections(adv_header, &adv_body).is_ok()); + } + + #[test] + fn max_number_encrypted_sections_sig() { + let mut adv_body = vec![]; + for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT { + let _ = add_sig_encrpyted_section(&mut adv_body, 5, &[0x55; EXTENDED_SALT_LEN]); + } + let adv_header = V1AdvHeader::new(0x20); + assert!(parse_sections(adv_header, &adv_body).is_ok()); + } + + #[test] + fn both_mic_and_sig_sections() { + let mut adv_body = vec![]; + let short_salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + let token_bytes = [0x55; V1_IDENTITY_TOKEN_LEN]; + let extended_salt = ExtendedV1Salt::from([0x55; EXTENDED_SALT_LEN]); + let total_section_1_len = add_mic_short_salt_section_to_adv(&mut adv_body); + let _ = add_sig_encrpyted_section(&mut adv_body, 5, extended_salt.bytes()); + + let adv_header = V1AdvHeader::new(0x20); + let section1 = &adv_body[0..total_section_1_len]; + let section2 = &adv_body[total_section_1_len..]; + let expected_sections = [ + IntermediateSection::from(MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion1[..1], + short_salt.into(), + token_bytes.into(), + (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(), + &[0xFF; 10], + ), + mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]), + }), + IntermediateSection::from(SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion2[..1], + extended_salt, + [0x33; V1_IDENTITY_TOKEN_LEN].into(), + 5, + &[0xFF; 5], + ), + }), + ]; + let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); + assert_eq!(parsed_sections.into_vec(), expected_sections); + } + + #[test] + fn parse_adv_sig_encrypted_sections() { + // 3 sections + let mut adv_body = vec![]; + let salt_bytes = [0x11; EXTENDED_SALT_LEN]; + + let section_1_len = add_sig_encrpyted_section(&mut adv_body, 10, &salt_bytes); + let section_2_len = add_sig_encrpyted_section(&mut adv_body, 11, &salt_bytes); + let _ = add_sig_encrpyted_section(&mut adv_body, 12, &salt_bytes); + + let adv_header = V1AdvHeader::new(0x20); + let section1 = &adv_body[..section_1_len]; + let section2 = &adv_body[section_1_len..][..section_2_len]; + let section3 = &adv_body[(section_1_len + section_2_len)..]; + let expected_sections = [ + SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion1[..1], + salt_bytes.into(), + [0x33; V1_IDENTITY_TOKEN_LEN].into(), + 10, + &[0xFF; 10], + ), + }, + SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion2[..1], + salt_bytes.into(), + [0x33; V1_IDENTITY_TOKEN_LEN].into(), + 11, + &[0xFF; 11], + ), + }, + SignatureEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion3[..1], + salt_bytes.into(), + [0x33; V1_IDENTITY_TOKEN_LEN].into(), + 12, + &[0xFF; 12], + ), + }, + ]; + let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); + assert_eq!(parsed_sections.into_vec(), expected_sections.map(IntermediateSection::from)); + } + + #[test] + fn parse_adv_ext_salt_mic_sections() { + // 3 sections + let mut adv_body = vec![]; + // section + adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + let salt = ExtendedV1Salt::from([0x11; EXTENDED_SALT_LEN]); + adv_body.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN]; + adv_body.extend_from_slice(&token_bytes_1); + let section_1_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8; + adv_body.push(10 + SectionMic::CONTENTS_LEN as u8); + // 10 bytes of 0xFF ciphertext + adv_body.extend_from_slice(&[0xFF; 10]); + // mic - 16x 0x33 + adv_body.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]); + + // section + adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + adv_body.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_2 = [0x77; V1_IDENTITY_TOKEN_LEN]; + adv_body.extend_from_slice(&token_bytes_2); + let section_2_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 11 + SectionMic::CONTENTS_LEN as u8; + adv_body.push(11 + SectionMic::CONTENTS_LEN as u8); + // 11 bytes of 0xFF ciphertext + adv_body.extend_from_slice(&[0xFF; 11]); + // mic - 16x 0x66 + adv_body.extend_from_slice(&[0x66; SectionMic::CONTENTS_LEN]); + + // section + adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + adv_body.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_3 = [0xAA; V1_IDENTITY_TOKEN_LEN]; + adv_body.extend_from_slice(&token_bytes_3); + let _ = EXT_SALT_SECTION_HEADER_LEN as u8 + 12 + SectionMic::CONTENTS_LEN as u8; + adv_body.push(12 + SectionMic::CONTENTS_LEN as u8); + // 12 bytes of 0xFF ciphertext + adv_body.extend_from_slice(&[0xFF; 12]); + // mic - 16x 0x99 + adv_body.extend_from_slice(&[0x99; SectionMic::CONTENTS_LEN]); + + let adv_header = V1AdvHeader::new(0x20); + let section1 = &adv_body[..section_1_len as usize]; + let section2 = &adv_body[section_1_len as usize..][..section_2_len as usize]; + let section3 = &adv_body[section_1_len as usize + section_2_len as usize..]; + let expected_sections = [ + MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion1[..1], + salt.into(), + token_bytes_1.into(), + (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(), + &[0xFF; 10], + ), + mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]), + }, + MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion2[..1], + salt.into(), + token_bytes_2.into(), + (11 + SectionMic::CONTENTS_LEN).try_into().unwrap(), + &[0xFF; 11], + ), + mic: SectionMic::from([0x66; SectionMic::CONTENTS_LEN]), + }, + MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion3[..1], + salt.into(), + token_bytes_3.into(), + (12 + SectionMic::CONTENTS_LEN).try_into().unwrap(), + &[0xFF; 12], + ), + mic: SectionMic::from([0x99; SectionMic::CONTENTS_LEN]), + }, + ]; + let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); + assert_eq!(parsed_sections.into_vec(), &expected_sections.map(IntermediateSection::from)); + } + + #[test] + fn parse_adv_short_salt_mic() { + // 3 sections + let short_salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + let token_bytes = [0x55; V1_IDENTITY_TOKEN_LEN]; + let mut adv_body = vec![]; + let section_1_len = add_mic_short_salt_section_to_adv(&mut adv_body); + let _ = add_mic_short_salt_section_to_adv(&mut adv_body); + let _ = add_mic_short_salt_section_to_adv(&mut adv_body); + + let adv_header = V1AdvHeader::new(0x20); + let section1 = &adv_body[..(1 + section_1_len)]; + let mut expected_sections = [None, None, None]; + for section in &mut expected_sections { + *section = Some(MicEncryptedSection { + contents: EncryptedSectionContents::new( + adv_header, + §ion1[..1], + short_salt.into(), + token_bytes.into(), + (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(), + &[0xFF; 10], + ), + mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]), + }) + } + let expected: Vec<IntermediateSection> = + expected_sections.into_iter().map(|x| IntermediateSection::from(x.unwrap())).collect(); + let parsed_sections = parse_sections(adv_header, &adv_body).unwrap(); + assert_eq!(parsed_sections.into_vec(), expected); + } +} + +mod error_condition { + use super::*; + #[test] + fn parse_adv_too_many_unencrypted() { + // 2 sections + let mut adv_body = vec![]; + + // section 1 - plaintext - 9 bytes + adv_body.push(V1_ENCODING_UNENCRYPTED); + adv_body.push(6 + 3); // section len + // de 1 byte header, type 5, len 5 + adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 6, len 1 + adv_body.extend_from_slice(&[0x81, 0x06, 0x01]); + + // section 2 - plaintext - 10 bytes + adv_body.push(V1_ENCODING_UNENCRYPTED); + adv_body.push(6 + 3); // section len + // de 1 byte header, type 5, len 5 + adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 6, len 1 + adv_body.extend_from_slice(&[0x81, 0x06, 0x01]); + + let adv_header = V1AdvHeader::new(0x20); + + assert_eq!( + nom::Err::Error(error::Error { input: &adv_body[11..], code: error::ErrorKind::Eof }), + parse_sections(adv_header, &adv_body).unwrap_err() + ); + } + + #[test] + fn parse_adv_too_many_encrypted() { + // 3 sections + let mut adv_body = vec![]; + for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT + 1 { + let _ = add_mic_short_salt_section_to_adv(&mut adv_body); + } + let adv_header = V1AdvHeader::new(0x20); + let _ = parse_sections(adv_header, &adv_body).expect_err("Expected an error"); + } + + #[test] + fn do_deserialize_zero_section_header() { + let mut adv: tinyvec::ArrayVec<[u8; 254]> = tinyvec::ArrayVec::new(); + adv.push(0x20); // V1 Advertisement + adv.push(0x00); // Section header of 0 + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + let _ = parse_sections(v1_header, remaining).expect_err("Expected an error"); + } + + #[test] + fn invalid_public_section() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let mut adv_body = vec![]; + // Add section length + let remove_section_len = rng.gen_bool(0.5); + // Add public identity + let add_public_identity = rng.gen_bool(0.5); + // Add DEs + let add_des = rng.gen_bool(0.5); + // Shuffle adv + let shuffle = rng.gen_bool(0.5); + + adv_body.push(0); + if add_public_identity { + adv_body[0] += 1; + adv_body.push(0x03); + } + if add_des { + adv_body[0] += 1; + adv_body.extend_from_slice(&[0x81]); + } + if remove_section_len { + let _ = adv_body.remove(0); + } + + let ordered_adv = adv_body.clone(); + + if shuffle { + adv_body.shuffle(&mut rng); + } + // A V1 public section is invalid if + // * section length is missing + // * the section is empty + // * the section identity is missing + // * the identity does not follow the section length + // * the section length is 0 + if remove_section_len || !add_public_identity || (ordered_adv != adv_body) { + let _ = parse_sections(V1AdvHeader::new(0x20), &adv_body) + .expect_err("Expected to fail because of missing section length or identity"); + } + } + } + + #[test] + fn parse_empty_section_as_encrypted() { + // empty section - should return an EOF error + let input = []; + assert_eq!( + nom::Err::Error(error::Error { + // attempted to read section contents + input: input.as_slice(), + code: error::ErrorKind::Eof, + }), + IntermediateSection::parser_encrypted_with_header(V1AdvHeader::new(0x20))(&input) + .unwrap_err() + ); + } + + #[test] + fn parse_unencrypted_as_encrypted() { + let mut input = vec![]; + // public identity + input.push(V1_ENCODING_UNENCRYPTED); + // section len + input.push(6 + 3); + // de 1 byte header, type 5, len 5 + input.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 22, len 1 + input.extend_from_slice(&[0x81, 0x16, 0x01]); + assert_eq!( + nom::Err::Error(error::Error { + // attempted to read section contents + input: input.as_slice(), + code: error::ErrorKind::MapOpt, + }), + IntermediateSection::parser_encrypted_with_header(V1AdvHeader::new(0x20))(&input) + .unwrap_err() + ); + } + + #[test] + fn parse_section_length_overrun() { + // section of length 0xF0 - legal but way longer than 2 + let input = [V1_ENCODING_UNENCRYPTED, 0xF0, 0x10, 0x11]; + assert_eq!( + nom::Err::Error(error::Error { + // attempted to read section contents after parsing header + input: &input.as_slice()[2..], + code: error::ErrorKind::Eof, + }), + SectionContents::parse(&input).unwrap_err() + ); + } + + #[test] + fn do_deserialize_empty_section() { + let adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + let adv = adv_builder.into_advertisement(); + let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap(); + let v1_header = if let NpVersionHeader::V1(h) = header { + h + } else { + panic!("incorrect header"); + }; + let _ = parse_sections(v1_header, remaining).expect_err("Expected an error"); + } + + #[test] + fn parse_adv_sig_encrypted_section_with_short_salt() { + // 3 sections + let mut adv_body = vec![]; + let salt_bytes = [0x11; SHORT_SALT_LEN]; + let section_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 10; + adv_body.push(section_len); + adv_body.push(V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN); + adv_body.extend_from_slice(&salt_bytes); + adv_body.extend_from_slice(&[0x33; V1_IDENTITY_TOKEN_LEN]); + adv_body.extend_from_slice(&[0x22; 10]); + let adv_header = V1AdvHeader::new(0x20); + let parsed_sections = parse_sections(adv_header, &adv_body); + assert!(parsed_sections.is_err()); + } + + // specify extended salt in the header but adv actual contains short salt + #[test] + fn parse_adv_mic_encrypted_wrong_salt_for_extended_header() { + // 3 sections + let mut adv = vec![]; + let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8; + adv.push(section_len); + adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + adv.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN]; + adv.extend_from_slice(&token_bytes_1); + // 10 bytes of 0xFF ciphertext + adv.extend_from_slice(&[0xFF; 10]); + // mic - 16x 0x33 + adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]); + + let adv_header = V1AdvHeader::new(0x20); + let parsed_sections = parse_sections(adv_header, &adv); + assert!(parsed_sections.is_err()); + } + + // specify extended salt in the header but adv actual contains short salt + #[test] + fn encrypted_then_unencrpyted_fails_to_parse() { + // 3 sections + let mut adv = vec![]; + let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8; + adv.push(section_len); + adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN); + let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + adv.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN]; + adv.extend_from_slice(&token_bytes_1); + // 10 bytes of 0xFF ciphertext + adv.extend_from_slice(&[0xFF; 10]); + // mic - 16x 0x33 + adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]); + + // Now add public section + // section len + adv.push(1 + 6 + 3); + // public identity + adv.push(V1_ENCODING_UNENCRYPTED); + // de 1 byte header, type 5, len 5 + adv.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 6, len 1 + adv.extend_from_slice(&[0x81, 0x06, 0x01]); + + let adv_header = V1AdvHeader::new(0x20); + let parsed_sections = parse_sections(adv_header, &adv); + assert!(parsed_sections.is_err()); + } + + // specify extended salt in the header but adv actual contains short salt + #[test] + fn unencrypted_then_encrpyted_fails_to_parse() { + let mut adv = vec![]; + + // Public section + // section len + adv.push(1 + 6 + 3); + // public identity + adv.push(V1_ENCODING_UNENCRYPTED); + // de 1 byte header, type 5, len 5 + adv.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); + // de 2 byte header, type 6, len 1 + adv.extend_from_slice(&[0x81, 0x06, 0x01]); + + // mic encrypted section + let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8; + adv.push(section_len); + adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN); + let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + adv.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN]; + adv.extend_from_slice(&token_bytes_1); + // 10 bytes of 0xFF ciphertext + adv.extend_from_slice(&[0xFF; 10]); + // mic - 16x 0x33 + adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]); + + let adv_header = V1AdvHeader::new(0x20); + let parsed_sections = parse_sections(adv_header, &adv); + assert!(parsed_sections.is_err()); + } +} + +mod coverage_gaming { + use super::*; + use alloc::format; + + #[test] + fn section_contents() { + let sc = SectionContents { + format_bytes: &[], + header: SectionHeader::Unencrypted, + contents: &[], + contents_len: 0, + }; + let _ = format!("{:?}", sc); + assert_eq!(sc, sc); + } + + #[test] + fn intermediate_section() { + let is = IntermediateSection::Plaintext(PlaintextSection::new(&[])); + let _ = format!("{:?}", is); + } + #[test] + fn ciphertext_section() { + let ms = MicEncryptedSection { + contents: EncryptedSectionContents::new( + V1AdvHeader::new(1), + &[], + ShortV1Salt::from([0x00; 2]).into(), + CiphertextExtendedIdentityToken([0x00; 16]), + 0, + &[], + ), + mic: [0x00; 16].into(), + }; + let cs = CiphertextSection::MicEncrypted(ms); + let _ = format!("{:?}", cs); + } +} + +pub(crate) trait IntermediateSectionExt<'adv> { + /// Returns `Some` if `self` is `Plaintext` + fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>>; + /// Returns `Some` if `self` is `Ciphertext` + fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>>; +} + +impl<'adv> IntermediateSectionExt<'adv> for IntermediateSection<'adv> { + fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>> { + match self { + IntermediateSection::Plaintext(s) => Some(s), + IntermediateSection::Ciphertext(_) => None, + } + } + + fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>> { + match self { + IntermediateSection::Plaintext(_) => None, + IntermediateSection::Ciphertext(s) => Some(s), + } + } +} + +// returns the number of bytes appended to adv +fn add_mic_short_salt_section_to_adv(adv: &mut Vec<u8>) -> usize { + // section + adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN); + let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]); + adv.extend_from_slice(salt.bytes().as_slice()); + let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN]; + adv.extend_from_slice(&token_bytes_1); + let section_len = 10 + SectionMic::CONTENTS_LEN as u8; + adv.push(section_len); + // 10 bytes of 0xFF ciphertext + adv.extend_from_slice(&[0xFF; 10]); + // mic - 16x 0x33 + adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]); + 1 + SHORT_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1 + 10 + SectionMic::CONTENTS_LEN +} + +// returns the total number of bytes appended to adv +fn add_sig_encrpyted_section( + adv_body: &mut Vec<u8>, + len: u8, + salt_bytes: &[u8; EXTENDED_SALT_LEN], +) -> usize { + adv_body.push(V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN); + adv_body.extend_from_slice(salt_bytes); + adv_body.extend_from_slice(&[0x33; V1_IDENTITY_TOKEN_LEN]); + adv_body.push(len); + // len bytes of 0xFF ciphertext -- in a real adv this would include the + // signature, but for the purposes of this parser, it's all just ciphertext + for _ in 0..len { + adv_body.push(0xFF); + } + 1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1 + len as usize +} + +// for convenient .into() in expected test data +impl<'a> From<SignatureEncryptedSection<'a>> for IntermediateSection<'a> { + fn from(s: SignatureEncryptedSection<'a>) -> Self { + IntermediateSection::Ciphertext(CiphertextSection::SignatureEncrypted(s)) + } +} + +impl<'a> From<MicEncryptedSection<'a>> for IntermediateSection<'a> { + fn from(s: MicEncryptedSection<'a>) -> Self { + IntermediateSection::Ciphertext(CiphertextSection::MicEncrypted(s)) + } +} + +impl<'a> From<PlaintextSection<'a>> for IntermediateSection<'a> { + fn from(s: PlaintextSection<'a>) -> Self { + IntermediateSection::Plaintext(s) + } +}
diff --git a/nearby/util/pourover_macro_core/src/lib.rs b/nearby/presence/np_adv/src/extended/deserialize/section/mod.rs similarity index 78% copy from nearby/util/pourover_macro_core/src/lib.rs copy to nearby/presence/np_adv/src/extended/deserialize/section/mod.rs index ae06345..1020e8d 100644 --- a/nearby/util/pourover_macro_core/src/lib.rs +++ b/nearby/presence/np_adv/src/extended/deserialize/section/mod.rs
@@ -1,10 +1,10 @@ -// Copyright 2024 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod jni_method; -pub use jni_method::jni_method; +pub(crate) mod header; +pub(crate) mod intermediate;
diff --git a/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs b/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs deleted file mode 100644 index 5fa2dbe..0000000 --- a/nearby/presence/np_adv/src/extended/deserialize/section_tests.rs +++ /dev/null
@@ -1,622 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use super::*; -use crate::deserialization_arena; -use crate::deserialization_arena::DeserializationArena; -use crate::extended::serialize::AdvertisementType; -use crate::extended::NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT; -use crate::{ - credential::{ - source::{DiscoveryCredentialSource, SliceCredentialSource}, - v1::{SignedBroadcastCryptoMaterial, SimpleSignedBroadcastCryptoMaterial, V1}, - DiscoveryCryptoMaterial, EmptyMatchedCredential, MatchableCredential, - MetadataMatchedCredential, SimpleBroadcastCryptoMaterial, - }, - extended::{ - data_elements::GenericDataElement, - deserialize::{test_stubs::IntermediateSectionExt, DataElement}, - serialize::{ - self, AdvBuilder, MicEncryptedSectionEncoder, PublicSectionEncoder, SectionBuilder, - SignedEncryptedSectionEncoder, WriteDataElement, - }, - MAX_DE_LEN, - }, - parse_adv_header, AdvHeader, WithMatchedCredential, -}; -use core::borrow::Borrow; -use core::convert::Into; -use crypto_provider::{CryptoProvider, CryptoRng}; -use crypto_provider_default::CryptoProviderImpl; -use rand::{seq::SliceRandom as _, Rng as _, SeedableRng as _}; -use std::prelude::rust_2021::*; -use std::vec; - -type KeyPair = np_ed25519::KeyPair<CryptoProviderImpl>; - -#[test] -fn deserialize_public_identity_section() { - do_deserialize_section_unencrypted::<PublicSectionEncoder>( - PublicSectionEncoder::default(), - PlaintextIdentityMode::Public, - 1, - ); -} - -// due to lifetime issues, this is somewhat challenging to share with the 90% identical signature -// test, but if someone feels like putting in the tinkering to make it happen, please do -#[test] -fn deserialize_mic_encrypted_rand_identities_finds_correct_one() { - let mut rng = rand::rngs::StdRng::from_entropy(); - let mut crypto_rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); - for _ in 0..100 { - let identities = (0..100).map(|_| (rng.gen(), KeyPair::generate())).collect::<Vec<_>>(); - - let chosen_index = rng.gen_range(0..identities.len()); - let (chosen_key_seed, _chosen_key_pair) = &identities[chosen_index]; - - // share a metadata key to emphasize that we're _only_ using the identity to - // differentiate - let metadata_key: [u8; 16] = rng.gen(); - let metadata_key = MetadataKey(metadata_key); - - let creds = identities - .iter() - .map(|(key_seed, key_pair)| { - SimpleSignedBroadcastCryptoMaterial::new( - *key_seed, - metadata_key, - key_pair.private_key(), - ) - }) - .enumerate() - .map(|(index, broadcast_cm)| { - let match_data = MetadataMatchedCredential::<Vec<u8>>::encrypt_from_plaintext::< - _, - _, - CryptoProviderImpl, - >(&broadcast_cm, &[index as u8]); - - let discovery_credential = - broadcast_cm.derive_v1_discovery_credential::<CryptoProviderImpl>(); - - MatchableCredential { discovery_credential, match_data } - }) - .collect::<Vec<_>>(); - - let cred_source = SliceCredentialSource::new(&creds); - - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(*chosen_key_seed, metadata_key); - - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( - &mut crypto_rng, - identity_type, - &broadcast_cm, - )) - .unwrap(); - - let mut expected_de_data = vec![]; - let (expected_des, orig_des) = - fill_section_random_des(&mut rng, &mut expected_de_data, &mut section_builder, 2); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let arena = deserialization_arena!(); - - let section = sections[0].as_ciphertext().unwrap(); - let matched_section = - try_deserialize_all_creds::<_, CryptoProviderImpl>(arena, section, &cred_source) - .unwrap() - .unwrap(); - - // Verify that the decrypted metadata contains the chosen index - let decrypted_metadata = matched_section.decrypt_metadata::<CryptoProviderImpl>().unwrap(); - assert_eq!([chosen_index as u8].as_slice(), &decrypted_metadata); - - // Verify that the section contents passed through unaltered - let section = matched_section.contents(); - assert_eq!(section.identity_type(), identity_type); - assert_eq!(section.verification_mode(), VerificationMode::Mic); - assert_eq!(section.metadata_key(), metadata_key); - assert_eq!( - section.contents.section_header, - (19 + 2 + 16 + total_de_len(&orig_des) + 16) as u8 - ); - let data_elements = section.collect_data_elements().unwrap(); - assert_eq!(data_elements, expected_des); - assert_eq!( - data_elements - .iter() - .map(|de| GenericDataElement::try_from(de.de_type(), de.contents()).unwrap()) - .collect::<Vec<_>>(), - orig_des - ); - } -} - -#[test] -fn deserialize_signature_encrypted_rand_identities_finds_correct_one() { - let mut rng = rand::rngs::StdRng::from_entropy(); - let mut crypto_rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); - for _ in 0..100 { - let identities = (0..100).map(|_| (rng.gen(), KeyPair::generate())).collect::<Vec<_>>(); - - let chosen_index = rng.gen_range(0..identities.len()); - let (chosen_key_seed, chosen_key_pair) = &identities[chosen_index]; - - // share a metadata key to emphasize that we're _only_ using the identity to - // differentiate - let metadata_key: [u8; 16] = rng.gen(); - let metadata_key = MetadataKey(metadata_key); - - let creds = identities - .iter() - .map(|(key_seed, key_pair)| { - SimpleSignedBroadcastCryptoMaterial::new( - *key_seed, - metadata_key, - key_pair.private_key(), - ) - }) - .enumerate() - .map(|(index, broadcast_cm)| { - let match_data = MetadataMatchedCredential::<Vec<u8>>::encrypt_from_plaintext::< - _, - _, - CryptoProviderImpl, - >(&broadcast_cm, &[index as u8]); - - let discovery_credential = - broadcast_cm.derive_v1_discovery_credential::<CryptoProviderImpl>(); - MatchableCredential { discovery_credential, match_data } - }) - .collect::<Vec<_>>(); - - let cred_source = SliceCredentialSource::new(&creds); - - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleSignedBroadcastCryptoMaterial::new( - *chosen_key_seed, - metadata_key, - chosen_key_pair.private_key(), - ); - - let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( - &mut crypto_rng, - identity_type, - &broadcast_cm, - )) - .unwrap(); - - let mut expected_de_data = vec![]; - let (expected_des, orig_des) = - fill_section_random_des(&mut rng, &mut expected_de_data, &mut section_builder, 2); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let arena = deserialization_arena!(); - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - let section = sections[0].as_ciphertext().unwrap(); - let matched_section = - try_deserialize_all_creds::<_, CryptoProviderImpl>(arena, section, &cred_source) - .unwrap() - .unwrap(); - - // Verify that the decrypted metadata contains the chosen index - let decrypted_metadata = matched_section.decrypt_metadata::<CryptoProviderImpl>().unwrap(); - assert_eq!([chosen_index as u8].as_slice(), &decrypted_metadata); - - // Verify that the section contents passed through unaltered - let section = matched_section.contents(); - assert_eq!(section.identity_type(), identity_type); - assert_eq!(section.verification_mode(), VerificationMode::Signature); - assert_eq!(section.metadata_key(), metadata_key); - assert_eq!( - section.contents.section_header, - (19 + 2 + 16 + 64 + total_de_len(&orig_des)) as u8 - ); - let data_elements = section.collect_data_elements().unwrap(); - assert_eq!(data_elements, expected_des); - assert_eq!( - data_elements - .iter() - .map(|de| GenericDataElement::try_from(de.de_type(), de.contents()).unwrap()) - .collect::<Vec<_>>(), - orig_des - ); - } -} - -#[test] -fn deserialize_encrypted_no_matching_identities_finds_nothing() { - let mut rng = rand::rngs::StdRng::from_entropy(); - let mut crypto_rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); - for _ in 0..100 { - let signed = rng.gen(); - let mut identities = (0..100).map(|_| (rng.gen(), KeyPair::generate())).collect::<Vec<_>>(); - - let chosen_index = rng.gen_range(0..identities.len()); - // remove so they won't be found later - let (chosen_key_seed, chosen_key_pair) = identities.remove(chosen_index); - - // share a metadata key to emphasize that we're _only_ using the identity to - // differentiate - let metadata_key: [u8; 16] = rng.gen(); - let metadata_key = MetadataKey(metadata_key); - - let credentials = identities - .iter() - .map(|(key_seed, key_pair)| { - SimpleSignedBroadcastCryptoMaterial::new( - *key_seed, - metadata_key, - key_pair.private_key(), - ) - .derive_v1_discovery_credential::<CryptoProviderImpl>() - }) - .map(|discovery_credential| MatchableCredential { - discovery_credential, - match_data: EmptyMatchedCredential, - }) - .collect::<Vec<_>>(); - - let cred_source = SliceCredentialSource::new(&credentials); - - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let broadcast_cm = SimpleSignedBroadcastCryptoMaterial::new( - chosen_key_seed, - metadata_key, - chosen_key_pair.private_key(), - ); - - // awkward split because SectionEncoder isn't object-safe, so we can't just have a - // Box<dyn SectionEncoder> and use that in one code path - if signed { - let identity = SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( - &mut crypto_rng, - identity_type, - &broadcast_cm, - ); - let mut section_builder = adv_builder.section_builder(identity).unwrap(); - let mut expected_de_data = vec![]; - let _ = - fill_section_random_des(&mut rng, &mut expected_de_data, &mut section_builder, 2); - section_builder.add_to_advertisement(); - } else { - let identity = MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( - &mut crypto_rng, - identity_type, - &broadcast_cm, - ); - let mut section_builder = adv_builder.section_builder(identity).unwrap(); - let mut expected_de_data = vec![]; - let _ = - fill_section_random_des(&mut rng, &mut expected_de_data, &mut section_builder, 2); - section_builder.add_to_advertisement(); - }; - - let adv = adv_builder.into_advertisement(); - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - - assert!(try_deserialize_all_creds::<_, CryptoProviderImpl>( - deserialization_arena!(), - sections[0].as_ciphertext().unwrap(), - &cred_source, - ) - .unwrap() - .is_none()); - } -} - -#[test] -fn section_des_expose_correct_data() { - // 2 sections, 3 DEs each - let mut de_data = vec![]; - // de 1 byte header, type 5, len 5 - de_data.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]); - // de 2 byte header, type 16, len 1 - de_data.extend_from_slice(&[0x81, 0x10, 0x01]); - - let section = SectionContents { - section_header: 99, - de_region_excl_identity: &de_data, - data_element_start_offset: 2, - }; - - // extract out the parts of the DE we care about - let des = section.iter_data_elements().collect::<Result<Vec<_>, _>>().unwrap(); - assert_eq!( - vec![ - DataElement { - offset: 2.into(), - de_type: 5_u32.into(), - contents: &[0x01, 0x02, 0x03, 0x04, 0x05] - }, - DataElement { offset: 3.into(), de_type: 16_u32.into(), contents: &[0x01] }, - ], - des - ); -} - -#[test] -fn do_deserialize_zero_section_header() { - let mut adv: tinyvec::ArrayVec<[u8; 254]> = tinyvec::ArrayVec::new(); - adv.push(0x20); // V1 Advertisement - adv.push(0x00); // Section header of 0 - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - let _ = parse_sections(v1_header, remaining).expect_err("Expected an error"); -} - -#[test] -fn do_deserialize_empty_section() { - let adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let adv = adv_builder.into_advertisement(); - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - let _ = parse_sections(v1_header, remaining).expect_err("Expected an error"); -} - -#[test] -fn do_deserialize_max_number_of_public_sections() { - let adv_builder = build_dummy_advertisement_sections(NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT); - let adv = adv_builder.into_advertisement(); - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, sections.len()); -} - -#[test] -fn try_deserialize_over_max_number_of_public_sections() { - let adv_builder = build_dummy_advertisement_sections(NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT); - let mut adv = adv_builder.into_advertisement().as_slice().to_vec(); - - // Push an extra section - adv.extend_from_slice( - [ - 0x01, // Section header - 0x03, // Public identity - ] - .as_slice(), - ); - - let (remaining, header) = parse_adv_header(&adv).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - let _ = parse_sections(v1_header, remaining) - .expect_err("Expected an error because number of sections is over limit"); -} - -pub(crate) fn random_de<R: rand::Rng>(rng: &mut R) -> GenericDataElement { - let mut array = [0_u8; MAX_DE_LEN]; - rng.fill(&mut array[..]); - let data: ArrayView<u8, MAX_DE_LEN> = - ArrayView::try_from_array(array, rng.gen_range(0..=MAX_DE_LEN)).unwrap(); - // skip the first few DEs that Google uses - GenericDataElement::try_from(rng.gen_range(20_u32..1000).into(), data.as_slice()).unwrap() -} - -fn do_deserialize_section_unencrypted<I: serialize::SectionEncoder>( - identity: I, - expected_identity: PlaintextIdentityMode, - de_offset: usize, -) { - let mut rng = rand::rngs::StdRng::from_entropy(); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(identity).unwrap(); - - let mut expected_de_data = vec![]; - let (expected_des, orig_des) = - fill_section_random_des(&mut rng, &mut expected_de_data, &mut section_builder, de_offset); - - section_builder.add_to_advertisement(); - - let adv = adv_builder.into_advertisement(); - - let (remaining, header) = parse_adv_header(adv.as_slice()).unwrap(); - - let v1_header = if let AdvHeader::V1(h) = header { - h - } else { - panic!("incorrect header"); - }; - - let sections = parse_sections(v1_header, remaining).unwrap(); - assert_eq!(1, sections.len()); - let section = sections[0].as_plaintext().unwrap(); - - assert_eq!(section.identity(), expected_identity); - let data_elements = section.collect_data_elements().unwrap(); - assert_eq!(data_elements, expected_des); - assert_eq!( - data_elements - .iter() - .map(|de| GenericDataElement::try_from(de.de_type(), de.contents()).unwrap()) - .collect::<Vec<_>>(), - orig_des - ); -} - -fn fill_section_random_des<'adv, R: rand::Rng, I: serialize::SectionEncoder>( - mut rng: &mut R, - sink: &'adv mut Vec<u8>, - section_builder: &mut SectionBuilder<&mut AdvBuilder, I>, - de_offset: usize, -) -> (Vec<DataElement<'adv>>, Vec<GenericDataElement>) { - let mut expected_des = vec![]; - let mut orig_des = vec![]; - let mut de_ranges = vec![]; - - for _ in 0..rng.gen_range(1..10) { - let de = random_de(&mut rng); - - let de_clone = de.clone(); - if section_builder.add_de(|_| de_clone).is_err() { - break; - } - - let orig_len = sink.len(); - de.write_de_contents(sink).unwrap(); - let contents_len = sink.len() - orig_len; - de_ranges.push(orig_len..orig_len + contents_len); - orig_des.push(de); - } - - for (index, (de, range)) in orig_des.iter().zip(de_ranges).enumerate() { - expected_des.push(DataElement { - offset: u8::try_from(index + de_offset).unwrap().into(), - de_type: de.de_header().de_type, - contents: &sink[range], - }); - } - (expected_des, orig_des) -} - -fn total_de_len(des: &[GenericDataElement]) -> usize { - des.iter() - .map(|de| { - let mut buf = vec![]; - let _ = de.write_de_contents(&mut buf); - de.de_header().serialize().len() + buf.len() - }) - .sum() -} - -type TryDeserOutput<'adv, M> = Option<WithMatchedCredential<M, DecryptedSection<'adv>>>; - -/// Returns: -/// - `Ok(Some)` if a matching credential was found -/// - `Ok(None)` if no matching credential was found, or if `cred_source` provides no credentials -/// - `Err` if an error occurred. -fn try_deserialize_all_creds<'a, S, P>( - arena: DeserializationArena<'a>, - section: &'a CiphertextSection, - cred_source: &'a S, -) -> Result<TryDeserOutput<'a, S::Matched>, BatchSectionDeserializeError> -where - S: DiscoveryCredentialSource<'a, V1>, - P: CryptoProvider, -{ - let mut allocator = arena.into_allocator(); - for (crypto_material, match_data) in cred_source.iter() { - match section - .try_resolve_identity_and_deserialize::<_, P>(&mut allocator, crypto_material.borrow()) - { - Ok(s) => { - let metadata_nonce = crypto_material.metadata_nonce::<P>(); - return Ok(Some(WithMatchedCredential::new(match_data, metadata_nonce, s))); - } - Err(e) => match e { - SectionDeserializeError::IncorrectCredential => continue, - SectionDeserializeError::ParseError => { - return Err(BatchSectionDeserializeError::ParseError) - } - SectionDeserializeError::ArenaOutOfSpace => { - return Err(BatchSectionDeserializeError::ArenaOutOfSpace) - } - }, - } - } - - Ok(None) -} - -fn build_dummy_advertisement_sections(number_of_sections: usize) -> AdvBuilder { - let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - for _ in 0..number_of_sections { - let section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); - section_builder.add_to_advertisement(); - } - adv_builder -} - -#[derive(Debug, PartialEq, Eq)] -enum BatchSectionDeserializeError { - /// Advertisement data is malformed - ParseError, - /// The given arena is not large enough to hold the decrypted data - ArenaOutOfSpace, -}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/test_stubs.rs b/nearby/presence/np_adv/src/extended/deserialize/test_stubs.rs deleted file mode 100644 index 68b6f5d..0000000 --- a/nearby/presence/np_adv/src/extended/deserialize/test_stubs.rs +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -extern crate std; - -use std::prelude::rust_2021::*; - -use crate::{ - extended::deserialize::{CiphertextSection, PlaintextSection}, - IntermediateSection, -}; - -pub(crate) trait IntermediateSectionExt<'adv> { - /// Returns `Some` if `self` is `Plaintext` - fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>>; - /// Returns `Some` if `self` is `Ciphertext` - fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>>; -} - -impl<'adv> IntermediateSectionExt<'adv> for IntermediateSection<'adv> { - fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>> { - match self { - IntermediateSection::Plaintext(s) => Some(s), - IntermediateSection::Ciphertext(_) => None, - } - } - - fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>> { - match self { - IntermediateSection::Plaintext(_) => None, - IntermediateSection::Ciphertext(s) => Some(s), - } - } -}
diff --git a/nearby/presence/np_adv/src/extended/deserialize/tests.rs b/nearby/presence/np_adv/src/extended/deserialize/tests.rs new file mode 100644 index 0000000..3164c2b --- /dev/null +++ b/nearby/presence/np_adv/src/extended/deserialize/tests.rs
@@ -0,0 +1,145 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Unit tests for top level credential iteration and adv deserialization + +#![allow(clippy::unwrap_used)] + +use crate::{ + credential::book::CredentialBook, + deserialization_arena, + deserialization_arena::ArenaOutOfSpace, + extended::serialize::{AddSectionError, AdvBuilder, AdvertisementType}, + header::NpVersionHeader, + tests::deser_v1_tests::{ + add_mic_rand_salt_to_adv, add_sig_rand_salt_to_adv, SectionConfig, TestIdentity, + }, +}; +use crypto_provider_default::CryptoProviderImpl; +use rand::{prelude::StdRng, seq::IteratorRandom, SeedableRng}; + +#[test] +fn v1_arena_out_of_space_error_sig() { + v1_arena_out_of_space_error_encrypted_adv( + // Need to use many DE's to be sure we go over the arena limit + add_sig_rand_salt_to_adv::<StdRng, CryptoProviderImpl, 5>, + ) +} + +#[test] +fn v1_arena_out_of_space_error_mic() { + v1_arena_out_of_space_error_encrypted_adv( + // Need to use many DE's to be sure we go over the arena limit + add_mic_rand_salt_to_adv::<StdRng, CryptoProviderImpl, 5>, + ) +} + +fn v1_arena_out_of_space_error_encrypted_adv( + add_to_adv: impl for<'a> Fn( + &mut StdRng, + &'a TestIdentity, + &mut AdvBuilder, + ) -> Result<SectionConfig<'a>, AddSectionError>, +) { + let mut rng = StdRng::from_entropy(); + let mut builder = AdvBuilder::new(AdvertisementType::Encrypted); + let identities = + crate::tests::deser_v1_tests::TestIdentities::generate::<1, _, CryptoProviderImpl>( + &mut rng, + ); + let _ = add_to_adv(&mut rng, &identities.0[0], &mut builder); + let adv = builder.into_advertisement().as_slice().to_vec(); + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + + let (remaining, header) = NpVersionHeader::parse(&adv).unwrap(); + + let h = + if let NpVersionHeader::V1(v1_header) = header { Some(v1_header) } else { None }.unwrap(); + + let mut sections_in_processing = + crate::extended::deserialize::SectionsInProcessing::<'_, _>::from_advertisement_contents::< + CryptoProviderImpl, + >(h, remaining) + .unwrap(); + + // fill up allocator so we will run out of space + let arena = deserialization_arena!(); + let mut allocator = arena.into_allocator(); + let _ = allocator.allocate(250).unwrap(); + + let (crypto_material, match_data) = cred_book.v1_iter().choose(&mut rng).unwrap(); + + let res = sections_in_processing.try_decrypt_with_credential::<_, CryptoProviderImpl>( + &mut allocator, + crypto_material, + match_data, + ); + assert_eq!(Err(ArenaOutOfSpace), res); +} + +mod coverage_gaming { + use crate::{ + array_vec::ArrayVecOption, + credential::matched::EmptyMatchedCredential, + extended::{ + deserialize::{ + section::intermediate::PlaintextSection, DecryptedSection, SectionDeserializeError, + V1AdvertisementContents, V1DeserializedSection, VerificationMode, + }, + salt::MultiSalt, + }, + }; + use alloc::format; + + #[test] + fn decrypted_section_derives() { + let d = DecryptedSection::new( + VerificationMode::Mic, + MultiSalt::Extended([0u8; 16].into()), + [0u8; 16].into(), + &[], + ); + let _ = format!("{:?}", d); + } + + #[test] + fn section_deserialize_error_derives() { + let e = SectionDeserializeError::IncorrectCredential; + assert_eq!(e, e); + let _ = format!("{:?}", e); + } + + #[test] + fn adv_contents_derives() { + let c: V1AdvertisementContents<'_, EmptyMatchedCredential> = + V1AdvertisementContents::new(ArrayVecOption::default(), 0); + let _ = format!("{:?}", c); + assert_eq!(c, c); + } + + #[test] + fn deserialized_section_derives() { + let d: V1DeserializedSection<'_, EmptyMatchedCredential> = + V1DeserializedSection::Plaintext(PlaintextSection::new(&[])); + assert_eq!(d, d); + let _ = format!("{:?}", d); + } + + #[test] + fn verification_mode_derives() { + let m = VerificationMode::Signature; + #[allow(clippy::clone_on_copy)] + let _ = format!("{:?}", m.clone()); + } +}
diff --git a/nearby/presence/np_adv/src/extended/mod.rs b/nearby/presence/np_adv/src/extended/mod.rs index 68b16c3..4a13ea5 100644 --- a/nearby/presence/np_adv/src/extended/mod.rs +++ b/nearby/presence/np_adv/src/extended/mod.rs
@@ -13,18 +13,20 @@ // limitations under the License. //! V1 advertisement support. -use crate::extended::de_type::DeType; use crate::DeLengthOutOfRange; use array_view::ArrayView; +use crypto_provider::CryptoRng; pub mod data_elements; pub mod de_type; pub mod deserialize; +pub mod salt; pub mod section_signature_payload; pub mod serialize; +// TODO make this easy to use w/ configurable arena size /// Maximum size of an NP advertisement, including the adv header -pub const BLE_ADV_SVC_CONTENT_LEN: usize = 254 +pub const BLE_5_ADV_SVC_MAX_CONTENT_LEN: usize = 254 // length and type bytes for svc data TLV - 1 - 1 // NP UUID @@ -36,16 +38,81 @@ /// Maximum number of public sections in an advertisement pub const NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT: usize = 1; -/// Maximum size of a NP section, including its header byte -pub const NP_ADV_MAX_SECTION_LEN: usize = BLE_ADV_SVC_CONTENT_LEN - // adv header byte - - 1; +/// Maximum size of a NP section, including its length header byte +pub const NP_ADV_MAX_SECTION_LEN: usize = NP_ADV_MAX_SECTION_CONTENTS_LEN + 1; + +// TODO should this be 255 (or 256, if we +1 the length)? +/// Maximum hypothetical size of a NP section's contents, excluding its header +/// byte. This is longer than can fit in a BLE 5 extended adv, but other media +/// could fit it, like mDNS. +const NP_ADV_MAX_SECTION_CONTENTS_LEN: usize = 255; + +/// Size of a V1 identity token +pub const V1_IDENTITY_TOKEN_LEN: usize = 16; + +// 4-bit encoding ids +/// Encoding ID for unencrypted sections with no salt +pub const V1_ENCODING_UNENCRYPTED: u8 = 0x00; +/// Encoding ID for encrypted sections with a MIC and a short salt +pub const V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN: u8 = 0x01; +/// Encoding ID for encrypted sections with a MIC and an extended salt +pub const V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN: u8 = 0x02; +/// Encoding ID for encrypted sections with a signature and an extended salt +pub const V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN: u8 = 0x03; + +// The maximum de length that fits into a non-extended de header +const MAX_NON_EXTENDED_LEN: u8 = 7; +// The maximum type code that fits into a non-extended de header +const MAX_NON_EXTENDED_TYPE_CODE: u32 = 15; + +fn de_requires_extended_bit(type_code: u32, de_len: u8) -> bool { + de_len > MAX_NON_EXTENDED_LEN || type_code > MAX_NON_EXTENDED_TYPE_CODE +} + +/// 16-byte plaintext identity token. +/// +/// Identity tokens are present in encrypted form in a section's header. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub struct V1IdentityToken([u8; V1_IDENTITY_TOKEN_LEN]); + +impl From<[u8; V1_IDENTITY_TOKEN_LEN]> for V1IdentityToken { + fn from(value: [u8; V1_IDENTITY_TOKEN_LEN]) -> Self { + Self(value) + } +} + +impl V1IdentityToken { + /// Returns a reference to the inner byte array + pub fn bytes(&self) -> &[u8; V1_IDENTITY_TOKEN_LEN] { + &self.0 + } + + /// Returns the inner byte array + pub const fn into_bytes(self) -> [u8; V1_IDENTITY_TOKEN_LEN] { + self.0 + } + + /// Returns the token bytes as a slice + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl AsRef<[u8]> for V1IdentityToken { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl crypto_provider::FromCryptoRng for V1IdentityToken { + fn new_random<R: CryptoRng>(rng: &mut R) -> Self { + Self(rng.gen()) + } +} /// Max V1 DE length (7 bit length field). pub(crate) const MAX_DE_LEN: usize = 127; -const METADATA_KEY_LEN: usize = 16; - /// Length of a DE's content -- must be in `[0, 127]` #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct DeLength { @@ -82,7 +149,7 @@ } /// Convert a tinyvec into an equivalent ArrayView -fn to_array_view<T, const N: usize>(vec: tinyvec::ArrayVec<[T; N]>) -> ArrayView<T, N> +pub(crate) fn to_array_view<T, const N: usize>(vec: tinyvec::ArrayVec<[T; N]>) -> ArrayView<T, N> where [T; N]: tinyvec::Array, { @@ -90,4 +157,15 @@ ArrayView::try_from_array(vec.into_inner(), len).expect("len is from original vec") } -pub(crate) const ENCRYPTION_INFO_DE_TYPE: DeType = DeType::const_from(0x10); +#[cfg(test)] +mod tests { + use super::*; + use rand::{distributions, Rng}; + + // support randomly generating tokens just for tests + impl distributions::Distribution<V1IdentityToken> for distributions::Standard { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> V1IdentityToken { + V1IdentityToken::from(rng.gen::<[u8; V1_IDENTITY_TOKEN_LEN]>()) + } + } +}
diff --git a/nearby/presence/np_adv/src/extended/salt.rs b/nearby/presence/np_adv/src/extended/salt.rs new file mode 100644 index 0000000..b35275f --- /dev/null +++ b/nearby/presence/np_adv/src/extended/salt.rs
@@ -0,0 +1,113 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Various representations of salts for extended advertisements. + +use nom::combinator; + +use crypto_provider::{aes::ctr::AesCtrNonce, CryptoProvider, CryptoRng, FromCryptoRng}; +use np_hkdf::v1_salt::ExtendedV1Salt; + +use crate::helpers::parse_byte_array; + +/// Common behavior for V1 section salts. +pub trait V1Salt: Copy + Into<MultiSalt> { + /// Derive the nonce used for section encryption. + /// + /// Both kinds of salts can compute the nonce needed for de/encrypting a + /// section, but only extended salts can have data derived from them. + fn compute_nonce<C: CryptoProvider>(&self) -> AesCtrNonce; +} + +impl V1Salt for ExtendedV1Salt { + fn compute_nonce<C: CryptoProvider>(&self) -> AesCtrNonce { + self.derive::<12, C>(None).expect("AES-CTR nonce is a valid HKDF size") + } +} + +pub(crate) const SHORT_SALT_LEN: usize = 2; + +/// A byte buffer the size of a V1 short salt +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct ShortV1Salt([u8; SHORT_SALT_LEN]); + +impl From<[u8; SHORT_SALT_LEN]> for ShortV1Salt { + fn from(value: [u8; SHORT_SALT_LEN]) -> Self { + Self(value) + } +} + +impl ShortV1Salt { + pub(crate) fn bytes(&self) -> &[u8; SHORT_SALT_LEN] { + &self.0 + } + + pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], Self> { + combinator::map(parse_byte_array::<SHORT_SALT_LEN>, Self)(input) + } +} + +impl V1Salt for ShortV1Salt { + fn compute_nonce<C: CryptoProvider>(&self) -> AesCtrNonce { + np_hkdf::extended_mic_section_short_salt_nonce::<C>(self.0) + } +} + +impl FromCryptoRng for ShortV1Salt { + fn new_random<R: CryptoRng>(rng: &mut R) -> Self { + rng.gen::<[u8; SHORT_SALT_LEN]>().into() + } +} + +/// Either a short or extended salt. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum MultiSalt { + /// A 2-byte salt + Short(ShortV1Salt), + /// A 16-byte salt + Extended(ExtendedV1Salt), +} + +impl MultiSalt { + /// Salt bytes as a slice, for when variable-size access is sensible + pub fn as_slice(&self) -> &[u8] { + match self { + MultiSalt::Short(s) => s.bytes().as_slice(), + MultiSalt::Extended(s) => s.bytes().as_slice(), + } + } +} + +impl From<ExtendedV1Salt> for MultiSalt { + fn from(value: ExtendedV1Salt) -> Self { + Self::Extended(value) + } +} + +impl From<ShortV1Salt> for MultiSalt { + fn from(value: ShortV1Salt) -> Self { + Self::Short(value) + } +} + +impl V1Salt for MultiSalt { + /// Both kinds of salts can compute the nonce needed for decrypting an + /// advertisement, but only extended salts can have data derived from them. + fn compute_nonce<C: CryptoProvider>(&self) -> AesCtrNonce { + match self { + Self::Short(s) => V1Salt::compute_nonce::<C>(s), + Self::Extended(s) => s.compute_nonce::<C>(), + } + } +}
diff --git a/nearby/presence/np_adv/src/extended/section_signature_payload.rs b/nearby/presence/np_adv/src/extended/section_signature_payload.rs index d8ec93c..3cdaead 100644 --- a/nearby/presence/np_adv/src/extended/section_signature_payload.rs +++ b/nearby/presence/np_adv/src/extended/section_signature_payload.rs
@@ -16,40 +16,31 @@ //! after the included context bytes, and utilities for //! performing signatures and signature verification. -use crate::extended::deserialize::EncryptionInfo; -use crate::MetadataKey; -use crate::NP_SVC_UUID; -use crypto_provider::{aes::ctr::AesCtrNonce, CryptoProvider}; +use crate::header::VERSION_HEADER_V1; +use crypto_provider::{ + aes::ctr::AesCtrNonce, + ed25519::{Ed25519Provider, PrivateKey, PublicKey, Signature}, +}; use sink::{Sink, SinkWriter}; +use crate::NP_SVC_UUID; + /// A struct representing the necessary contents /// of an v1 advertisement section np_ed25519 signature payload which /// come after the context prefix (shared among all advs). pub(crate) struct SectionSignaturePayload<'a> { - /// Advertisement header byte - adv_header_byte: u8, - /// Header byte for the v1 section being signed - section_header: u8, - /// Reference to the complete contents of the [`EncryptionInfo`] DE. - encryption_info: &'a [u8; EncryptionInfo::TOTAL_DE_LEN], - /// Reference to the derived salt (IV) for the section - nonce_ref: &'a AesCtrNonce, - /// Reference to all remaining information after the derived salt, but - /// not including the signature itself [which gets tacked onto the end]. - after_iv_info: AfterIVInfo<'a>, -} - -/// Representation of the plaintext information in an advertisement -/// signature payload which comes after the derived salt -enum AfterIVInfo<'a> { - /// Reference to a raw byte array containing all information - /// to be included in the signature payload after the derived salt, - /// and before the signature itself. - Raw(&'a [u8]), - /// Plaintext identity DE header followed by the metadata key, - /// then the rest of the section plaintext (including - /// the plaintext identity DE payload). - IdentityHeaderMetadataKeyAndRemainder([u8; 2], MetadataKey, &'a [u8]), + /// first 1-2 bytes of format + format_bytes: &'a [u8], + /// Salt bytes + salt_bytes: &'a [u8], + /// Nonce for en/decrypting the section + nonce: &'a AesCtrNonce, + /// plaintext identity token + plaintext_identity_token: &'a [u8], + /// the len of the rest of the section contents stored as an u8 + section_payload_len: u8, + /// plaintext identity token + plaintext_data_elements: &'a [u8], } const ADV_SIGNATURE_CONTEXT: np_ed25519::SignatureContext = { @@ -60,66 +51,48 @@ }; impl<'a> SectionSignaturePayload<'a> { - /// Construct a section signature payload using parts typically found during - /// deserialization of advertisements. - pub(crate) fn from_deserialized_parts( - adv_header_byte: u8, - section_header: u8, - encryption_info: &'a [u8; EncryptionInfo::TOTAL_DE_LEN], - nonce_ref: &'a AesCtrNonce, - identity_header: [u8; 2], - plaintext_metadata_key: MetadataKey, - raw_plaintext_remainder: &'a [u8], + /// Construct a section signature payload with separate section len and + /// remaining contents of the section header. + /// + /// The section header should be in its on-the-wire form. + pub(crate) fn new( + format_bytes: &'a [u8], + salt_bytes: &'a [u8], + nonce: &'a AesCtrNonce, + plaintext_identity_token: &'a [u8], + section_payload_len: u8, + plaintext_data_elements: &'a [u8], ) -> Self { Self { - adv_header_byte, - section_header, - encryption_info, - nonce_ref, - after_iv_info: AfterIVInfo::IdentityHeaderMetadataKeyAndRemainder( - identity_header, - plaintext_metadata_key, - raw_plaintext_remainder, - ), - } - } - - /// Construct a section signature payload using parts typically found during - /// serialization of advertisements. - pub(crate) fn from_serialized_parts( - adv_header_byte: u8, - section_header: u8, - encryption_info: &'a [u8; EncryptionInfo::TOTAL_DE_LEN], - nonce_ref: &'a AesCtrNonce, - raw_after_iv_info: &'a [u8], - ) -> Self { - Self { - adv_header_byte, - section_header, - encryption_info, - nonce_ref, - after_iv_info: AfterIVInfo::Raw(raw_after_iv_info), + format_bytes, + salt_bytes, + nonce, + plaintext_identity_token, + section_payload_len, + plaintext_data_elements, } } /// Generates a signature for this section signing payload using /// the given Ed25519 key-pair. - pub(crate) fn sign<C: CryptoProvider>( - self, - key_pair: &np_ed25519::KeyPair<C>, - ) -> np_ed25519::Signature<C> { - key_pair - .sign_with_context(&ADV_SIGNATURE_CONTEXT, self) + pub(crate) fn sign<E: Ed25519Provider>(self, private_key: &PrivateKey) -> Signature { + np_ed25519::sign_with_context::<E, _>(private_key, &ADV_SIGNATURE_CONTEXT, self) .expect("section signature payloads should fit in signature buffer") } + /// Verifies a signature for this section signing payload using /// the given Ed25519 public key. - pub(crate) fn verify<C: CryptoProvider>( + pub(crate) fn verify<E: Ed25519Provider>( self, - signature: &np_ed25519::Signature<C>, - public_key: &np_ed25519::PublicKey<C>, + signature: Signature, + public_key: &PublicKey, ) -> Result<(), np_ed25519::SignatureVerificationError> { - public_key.verify_signature_with_context(&ADV_SIGNATURE_CONTEXT, self, signature) + np_ed25519::verify_signature_with_context::<E, _>( + public_key, + &ADV_SIGNATURE_CONTEXT, + self, + signature, + ) } } @@ -128,23 +101,12 @@ fn write_payload<S: Sink<u8> + ?Sized>(self, sink: &mut S) -> Option<()> { sink.try_extend_from_slice(&NP_SVC_UUID)?; - sink.try_push(self.adv_header_byte)?; - sink.try_push(self.section_header)?; - sink.try_extend_from_slice(self.encryption_info)?; - sink.try_extend_from_slice(self.nonce_ref)?; - - // identity DE and the rest of the DEs except for the suffix - match self.after_iv_info { - AfterIVInfo::Raw(s) => sink.try_extend_from_slice(s), - AfterIVInfo::IdentityHeaderMetadataKeyAndRemainder( - identity_header, - metadata_key, - remainder, - ) => { - sink.try_extend_from_slice(&identity_header)?; - sink.try_extend_from_slice(&metadata_key.0)?; - sink.try_extend_from_slice(remainder) - } - } + sink.try_push(VERSION_HEADER_V1)?; + sink.try_extend_from_slice(self.format_bytes)?; + sink.try_extend_from_slice(self.salt_bytes)?; + sink.try_extend_from_slice(self.nonce)?; + sink.try_extend_from_slice(self.plaintext_identity_token)?; + sink.try_push(self.section_payload_len)?; + sink.try_extend_from_slice(self.plaintext_data_elements) } }
diff --git a/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs b/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs index ee44c75..f094992 100644 --- a/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs +++ b/nearby/presence/np_adv/src/extended/serialize/adv_tests.rs
@@ -16,92 +16,107 @@ extern crate std; use super::*; +use crate::extended::serialize::section::header::SectionHeader; use crate::extended::serialize::section_tests::{fill_section_builder, DummyDataElement}; -use np_hkdf::v1_salt::DataElementOffset; +use crate::extended::V1_ENCODING_UNENCRYPTED; +use crypto_provider_default::CryptoProviderImpl; use std::{prelude::rust_2021::*, vec}; #[test] -fn adv_encode_no_salt() { +fn adv_encode_unencrypted() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); let mut public_identity_section_builder = - adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); public_identity_section_builder .add_de(|_| DummyDataElement { de_type: 30_u32.into(), data: vec![] }) .unwrap(); - public_identity_section_builder.add_to_advertisement(); + public_identity_section_builder.add_to_advertisement::<CryptoProviderImpl>(); assert_eq!( &[ - 0x20, // adv header - 0x3, // section header - 0x3, // public identity - 0x80, 30, // de header + 0x20, // NP version header + V1_ENCODING_UNENCRYPTED, + 0x02, // section len + 0x80, // de header, 0 length + 30, ], adv_builder.into_advertisement().as_slice() ) } #[test] -fn adding_any_allowed_section_length_always_works_for_single_section() { - // up to section len - 1 to leave room for section header - for section_contents_len in 0..NP_ADV_MAX_SECTION_LEN - 1 { +fn adding_any_ble5_allowed_section_length_always_works_for_single_section() { + // up to section len - 2 to leave room for NP version header, section length, + // and header + for section_contents_len in 0..=BLE_5_ADV_SVC_MAX_CONTENT_LEN - 3 { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = - adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); - fill_section_builder(section_contents_len, &mut section_builder); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); + fill_section_builder(section_contents_len, &mut section_builder).unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let adv = adv_builder.into_advertisement(); assert_eq!( - section_contents_len + 1 + 1 + 1, // adv and section headers and identity + section_contents_len + 1 + 1 + 1, // NP version header, section length, section header adv.as_slice().len(), "adv: {:?}\nsection contents len: {}", adv.as_slice(), section_contents_len ); } + + // one longer won't fit, though + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); + assert_eq!( + AddDataElementError::InsufficientSectionSpace, + fill_section_builder(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 2, &mut section_builder).unwrap_err() + ); } #[test] -fn building_capacity_0_section_works() { +fn building_capacity_0_ble5_section_works() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); - // leave room for section header and the public identity - fill_section_builder(NP_ADV_MAX_SECTION_LEN - 2, &mut section_builder); + // leave room for NP version header, section length and header + fill_section_builder(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 3, &mut section_builder).unwrap(); - assert_eq!(NP_ADV_MAX_SECTION_LEN, section_builder.section.capacity); - assert_eq!(NP_ADV_MAX_SECTION_LEN, section_builder.section.len()); + // this section can fill everything except the NP version header + assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 1, section_builder.section.capacity); + assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 1, section_builder.section.len()); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); - assert_eq!(BLE_ADV_SVC_CONTENT_LEN, adv_builder.into_advertisement().as_slice().len()); + assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN, adv_builder.into_advertisement().as_slice().len()); } +// TODO tests for other encoding types interacting with maximum possible section len + /// A placeholder identity with a huge prefix #[derive(Default, PartialEq, Eq, Debug)] struct EnormousIdentity {} impl SectionEncoder for EnormousIdentity { - const PREFIX_LEN: usize = 200; const SUFFIX_LEN: usize = 0; - const INITIAL_DE_OFFSET: DataElementOffset = DataElementOffset::ZERO; const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Plaintext; + type DerivedSalt = (); - fn postprocess( + fn header(&self) -> SectionHeader { + unimplemented!("Should never be hit") + } + fn postprocess<C: CryptoProvider>( &mut self, - _adv_header_byte: u8, - _section_header: u8, - _section_contents: &mut [u8], + _section_header_without_length: &mut [u8], + _section_len: u8, + _remaining_content_bytes: &mut [u8], ) { panic!("should never be called, just used for its huge prefix") } - type DerivedSalt = (); fn de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt { panic!("should never be called, just used for its huge prefix") }
diff --git a/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs b/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs index cb6c9ef..515ae97 100644 --- a/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs +++ b/nearby/presence/np_adv/src/extended/serialize/de_header_tests.rs
@@ -17,7 +17,6 @@ use super::*; use crate::extended::deserialize; use core::cmp; -use rand_ext::rand; use rand_ext::rand::{distributions, Rng as _}; #[test] @@ -69,10 +68,14 @@ assert_eq!(header_len as usize, buf.len()); - let (_, deser) = deserialize::DeHeader::parse(buf.as_slice()).unwrap(); + let (_, deser) = deserialize::data_element::DeHeader::parse(buf.as_slice()).unwrap(); assert_eq!( - deserialize::DeHeader { de_type, contents_len: len, header_bytes: buf }, + deserialize::data_element::DeHeader { + de_type, + contents_len: len, + header_bytes: buf + }, deser ) } @@ -89,10 +92,10 @@ let header_len = expected_header_len(hdr); assert_eq!(header_len as usize, buf.len()); - let (_, deser) = deserialize::DeHeader::parse(buf.as_slice()).unwrap(); + let (_, deser) = deserialize::data_element::DeHeader::parse(buf.as_slice()).unwrap(); assert_eq!( - deserialize::DeHeader { + deserialize::data_element::DeHeader { de_type: hdr.de_type, contents_len: hdr.len, header_bytes: buf
diff --git a/nearby/presence/np_adv/src/extended/serialize/mod.rs b/nearby/presence/np_adv/src/extended/serialize/mod.rs index 363862f..d94fee2 100644 --- a/nearby/presence/np_adv/src/extended/serialize/mod.rs +++ b/nearby/presence/np_adv/src/extended/serialize/mod.rs
@@ -19,15 +19,15 @@ //! Serialize some DEs without an adv salt: //! //! ``` +//! use crypto_provider_default::CryptoProviderImpl; //! use np_adv::{ -//! extended::{data_elements::*, serialize::*, de_type::DeType }, -//! PublicIdentity +//! extended::{data_elements::*, serialize::*, de_type::DeType, V1_ENCODING_UNENCRYPTED}, +//! shared_data::TxPower //! }; -//! use np_adv::shared_data::TxPower; //! //! // no section identities or DEs need salt in this example //! let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); -//! let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); +//! let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); //! //! section_builder.add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); //! @@ -36,13 +36,13 @@ //! GenericDataElement::try_from( DeType::from(1000_u32), &[10, 11, 12, 13]) //! ).unwrap(); //! -//! section_builder.add_to_advertisement(); +//! section_builder.add_to_advertisement::<CryptoProviderImpl>(); //! //! assert_eq!( //! &[ -//! 0x20, // adv header -//! 10, // section header -//! 0x03, // public identity +//! 0x20, // version header +//! V1_ENCODING_UNENCRYPTED, //section format +//! 0x09, // section length //! 0x15, 3, // tx power //! 0x84, 0x87, 0x68, 10, 11, 12, 13, // other DE //! ], @@ -54,34 +54,32 @@ //! //! ``` //! use np_adv::{ -//! credential::{SimpleBroadcastCryptoMaterial, v1::V1}, -//! de_type::EncryptedIdentityDataElementType, -//! extended::{data_elements::*, serialize::*, de_type::DeType }, -//! MetadataKey, +//! credential::{ v1::{V1, V1BroadcastCredential}}, +//! extended::{data_elements::*, serialize::*, de_type::DeType, V1IdentityToken }, //! }; //! use rand::{Rng as _, SeedableRng as _}; -//! use crypto_provider::{CryptoProvider, CryptoRng}; +//! use crypto_provider::{CryptoProvider, CryptoRng, ed25519}; //! use crypto_provider_default::CryptoProviderImpl; //! use np_adv::shared_data::TxPower; //! //! let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); //! -//! // these would come from the credential//! +//! // these would come from the credential +//! //! let mut rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); -//! let metadata_key: [u8; 16] = rng.gen(); -//! let metadata_key = MetadataKey(metadata_key); +//! let identity_token = rng.gen(); //! let key_seed: [u8; 32] = rng.gen(); //! // use your preferred crypto impl //! let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); //! -//! let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new( +//! let broadcast_cm = V1BroadcastCredential::new( //! key_seed, -//! metadata_key, +//! identity_token, +//! ed25519::PrivateKey::generate::<<CryptoProviderImpl as CryptoProvider>::Ed25519>(), //! ); //! -//! let mut section_builder = adv_builder.section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( +//! let mut section_builder = adv_builder.section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::<CryptoProviderImpl>( //! &mut rng, -//! EncryptedIdentityDataElementType::Private, //! &broadcast_cm, //! )).unwrap(); //! @@ -91,10 +89,10 @@ //! section_builder.add_de_res(|salt| //! GenericDataElement::try_from( //! DeType::from(1000_u32), -//! &do_fancy_crypto(salt.derive::<16>().expect("16 is a valid HKDF length"))) +//! &do_fancy_crypto(salt.derive::<16, CryptoProviderImpl>().expect("16 is a valid HKDF length"))) //! ).unwrap(); //! -//! section_builder.add_to_advertisement(); +//! section_builder.add_to_advertisement::<CryptoProviderImpl>(); //! //! // can't assert much about this since most of it is random //! assert_eq!( @@ -111,37 +109,33 @@ //! .try_into().expect("array sizes match") //! } //! ``` -use crate::extended::deserialize::RawV1Salt; -use crate::extended::{NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT}; -use crate::{ - credential::{ - v1::{SignedBroadcastCryptoMaterial, V1}, - BroadcastCryptoMaterial, - }, - de_type::{EncryptedIdentityDataElementType, IdentityDataElementType}, - extended::{ - data_elements::EncryptionInfoDataElement, - de_type::{DeType, ExtendedDataElementType}, - deserialize::{EncryptedIdentityMetadata, EncryptionInfo, SectionMic}, - section_signature_payload::*, - to_array_view, DeLength, BLE_ADV_SVC_CONTENT_LEN, NP_ADV_MAX_SECTION_LEN, - }, - DeLengthOutOfRange, MetadataKey, NP_SVC_UUID, -}; -use array_view::ArrayView; use core::fmt::{self, Display}; -use crypto_provider::{ - aes::{ - ctr::{AesCtr, AesCtrNonce, NonceAndCounter}, - Aes128Key, - }, - hmac::Hmac, - CryptoProvider, CryptoRng, -}; -use np_hkdf::v1_salt; -use np_hkdf::v1_salt::{DataElementOffset, V1Salt}; + +use array_view::ArrayView; +use crypto_provider::CryptoProvider; +use np_hkdf::v1_salt::{DataElementOffset, ExtendedV1Salt}; use sink::Sink; +use crate::extended::{ + de_requires_extended_bit, de_type::DeType, serialize::section::EncodedSection, to_array_view, + DeLength, BLE_5_ADV_SVC_MAX_CONTENT_LEN, NP_ADV_MAX_SECTION_LEN, + NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, +}; + +mod section; + +use crate::header::VERSION_HEADER_V1; +pub use section::{ + encoder::{ + MicEncryptedSectionEncoder, SectionEncoder, SignedEncryptedSectionEncoder, + UnencryptedSectionEncoder, + }, + AddDataElementError, SectionBuilder, +}; + +#[cfg(test)] +use crate::header::V1AdvHeader; + #[cfg(test)] pub(crate) mod adv_tests; #[cfg(test)] @@ -154,8 +148,9 @@ /// Builder for V1 advertisements. #[derive(Debug)] pub struct AdvBuilder { + // TODO make this configurable, and test making sections whose length is not restricted by BLE limitations /// Contains the adv header byte - adv: tinyvec::ArrayVec<[u8; BLE_ADV_SVC_CONTENT_LEN]>, + adv: tinyvec::ArrayVec<[u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN]>, /// To track the number of sections that are in the advertisement section_count: usize, /// Advertisement type: Public or Encrypted @@ -172,46 +167,10 @@ /// Build an [AdvBuilder]. pub fn new(advertisement_type: AdvertisementType) -> Self { let mut adv = tinyvec::ArrayVec::new(); - // version 1, 0bVVVRRRRR - adv.push(0b00100000); + adv.push(VERSION_HEADER_V1); Self { adv, section_count: 0, advertisement_type } } - fn prepare_section_builder_buffer_and_de_offset<SE: SectionEncoder>( - &self, - ) -> Result<(CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>, DataElementOffset), AddSectionError> - { - // section header and identity prefix - let prefix_len = 1 + SE::PREFIX_LEN; - let minimum_section_len = prefix_len + SE::SUFFIX_LEN; - // the max overall len available to the section - let available_len = self.adv.capacity() - self.adv.len(); - - if available_len < minimum_section_len { - return Err(AddSectionError::InsufficientAdvSpace); - } - - if self.section_count >= self.advertisement_type.max_sections() { - return Err(AddSectionError::MaxSectionCountExceeded); - } - - if self.advertisement_type != SE::ADVERTISEMENT_TYPE { - return Err(AddSectionError::IncompatibleSectionType); - } - - let mut section: tinyvec::ArrayVec<[u8; 249]> = tinyvec::ArrayVec::new(); - // placeholder for section header and identity prefix - section.resize(prefix_len, 0); - - let section = CapacityLimitedVec { - vec: section, - // won't underflow: checked above - capacity: available_len - SE::SUFFIX_LEN, - }; - let next_de_offset = SE::INITIAL_DE_OFFSET; - Ok((section, next_de_offset)) - } - /// Create a section builder whose contents may be added to this advertisement. /// /// The builder will not accept more DEs than can fit given the space already used in the @@ -223,10 +182,8 @@ &mut self, section_encoder: SE, ) -> Result<SectionBuilder<&mut AdvBuilder, SE>, AddSectionError> { - let (section, next_de_offset) = - self.prepare_section_builder_buffer_and_de_offset::<SE>()?; - - Ok(SectionBuilder { section, section_encoder, adv_builder: self, next_de_offset }) + let (header_len, contents) = self.prepare_section_builder_buffer(§ion_encoder)?; + Ok(SectionBuilder::new(header_len, contents, section_encoder, self)) } /// Create a section builder which actually takes ownership of this advertisement builder. @@ -240,9 +197,9 @@ self, section_encoder: SE, ) -> Result<SectionBuilder<AdvBuilder, SE>, (AdvBuilder, AddSectionError)> { - match self.prepare_section_builder_buffer_and_de_offset::<SE>() { - Ok((section, next_de_offset)) => { - Ok(SectionBuilder { section, section_encoder, adv_builder: self, next_de_offset }) + match self.prepare_section_builder_buffer::<SE>(§ion_encoder) { + Ok((header_len, section)) => { + Ok(SectionBuilder::new(header_len, section, section_encoder, self)) } Err(err) => Err((self, err)), } @@ -259,6 +216,37 @@ self.section_count } + /// Returns the length of the header (excluding the leading length byte), + /// and a buffer already populated with a placeholder section length byte and the rest + /// of the header. + fn prepare_section_builder_buffer<SE: SectionEncoder>( + &self, + section_encoder: &SE, + ) -> Result<(usize, CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), AddSectionError> { + if self.section_count >= self.advertisement_type.max_sections() { + return Err(AddSectionError::MaxSectionCountExceeded); + } + if self.advertisement_type != SE::ADVERTISEMENT_TYPE { + return Err(AddSectionError::IncompatibleSectionType); + } + + // The header contains all the header bytes except for the final length byte. + let header = section_encoder.header(); + let header_slice = header.as_slice(); + + // the max overall len available to the section + let available_len = self.adv.capacity() - self.adv.len(); + + let mut prefix = available_len + .checked_sub(SE::SUFFIX_LEN) + .and_then(CapacityLimitedVec::new) + .ok_or(AddSectionError::InsufficientAdvSpace)?; + prefix.try_extend_from_slice(header_slice).ok_or(AddSectionError::InsufficientAdvSpace)?; + // Placeholder for section length, which we do not know yet + prefix.try_push(0).ok_or(AddSectionError::InsufficientAdvSpace)?; + Ok((header_slice.len(), prefix)) + } + /// Add the section, which must have come from a SectionBuilder generated from this, into this /// advertisement. fn add_section(&mut self, section: EncodedSection) { @@ -268,8 +256,9 @@ self.section_count += 1; } - fn header_byte(&self) -> u8 { - self.adv[0] + #[cfg(test)] + fn adv_header(&self) -> V1AdvHeader { + V1AdvHeader::new(self.adv[0]) } } @@ -288,7 +277,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AddSectionError::InsufficientAdvSpace => { - write!(f, "The advertisement (max {BLE_ADV_SVC_CONTENT_LEN} bytes) doesn't have enough remaining space to hold the section") + write!(f, "The advertisement (max {BLE_5_ADV_SVC_MAX_CONTENT_LEN} bytes) doesn't have enough remaining space to hold the section") } AddSectionError::MaxSectionCountExceeded => { write!(f, "The advertisement can only hold a maximum of {NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT} number of sections") @@ -303,7 +292,7 @@ /// An encoded NP V1 advertisement, starting with the NP advertisement header byte. #[derive(Debug, PartialEq, Eq)] pub struct EncodedAdvertisement { - adv: ArrayView<u8, BLE_ADV_SVC_CONTENT_LEN>, + adv: ArrayView<u8, BLE_5_ADV_SVC_MAX_CONTENT_LEN>, } impl EncodedAdvertisement { @@ -313,158 +302,11 @@ } /// Converts this encoded advertisement into /// a raw byte-array. - pub fn into_array_view(self) -> ArrayView<u8, BLE_ADV_SVC_CONTENT_LEN> { + pub fn into_array_view(self) -> ArrayView<u8, BLE_5_ADV_SVC_MAX_CONTENT_LEN> { self.adv } } -/// The encoded form of an advertisement section -type EncodedSection = ArrayView<u8, NP_ADV_MAX_SECTION_LEN>; - -/// Accumulates data elements and encodes them into a section. -#[derive(Debug)] -pub struct SectionBuilder<R: AsMut<AdvBuilder>, SE: SectionEncoder> { - /// Contains the section header, the identity-specified overhead, and any DEs added - pub(crate) section: CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>, - section_encoder: SE, - /// mut ref-able to enforce only one active section builder at a time - adv_builder: R, - next_de_offset: DataElementOffset, -} - -impl<'a, SE: SectionEncoder> SectionBuilder<&'a mut AdvBuilder, SE> { - /// Add this builder to the advertisement that created it. - pub fn add_to_advertisement(self) { - let _ = self.add_to_advertisement_internal(); - } -} - -impl<SE: SectionEncoder> SectionBuilder<AdvBuilder, SE> { - /// Gets the 0-based index of the section currently under construction - /// in the context of the containing advertisement. - pub fn section_index(&self) -> usize { - self.adv_builder.section_count() - } - /// Add this builder to the advertisement that created it, - /// and returns the containing advertisement back to the caller. - pub fn add_to_advertisement(self) -> AdvBuilder { - self.add_to_advertisement_internal() - } -} - -impl<R: AsMut<AdvBuilder>, SE: SectionEncoder> SectionBuilder<R, SE> { - /// Add this builder to the advertisement that created it. - /// Returns the mut-refable to the advertisement builder - /// which the contents of this section builder were added to. - fn add_to_advertisement_internal(mut self) -> R { - let adv_builder = self.adv_builder.as_mut(); - let adv_builder_header_byte = adv_builder.header_byte(); - adv_builder.add_section(Self::build_section( - adv_builder_header_byte, - self.section.into_inner(), - self.section_encoder, - )); - self.adv_builder - } - - /// Gets the derived salt which will be employed for the next DE offset. - /// - /// Suitable for scenarios (like FFI) where a closure would be inappropriate - /// for DE construction, and interaction with the client is preferred. - pub fn next_de_salt(&self) -> SE::DerivedSalt { - self.section_encoder.de_salt(self.next_de_offset) - } - - /// Add a data element to the section with a closure that returns a `Result`. - /// - /// The provided `build_de` closure will be invoked with the derived salt for this DE. - pub fn add_de_res<W: WriteDataElement, E, F: FnOnce(SE::DerivedSalt) -> Result<W, E>>( - &mut self, - build_de: F, - ) -> Result<(), AddDataElementError<E>> { - let writer = build_de(self.next_de_salt()).map_err(AddDataElementError::BuildDeError)?; - - let orig_len = self.section.len(); - // since we own the writer, and it's immutable, no race risk writing header w/ len then - // the contents as long as it's not simply an incorrect impl - let de_header = writer.de_header(); - let content_len = self - .section - .try_extend_from_slice(de_header.serialize().as_slice()) - .ok_or(AddDataElementError::InsufficientSectionSpace) - .and_then(|_| { - let after_header_len = self.section.len(); - writer - .write_de_contents(&mut self.section) - .ok_or(AddDataElementError::InsufficientSectionSpace) - .map(|_| self.section.len() - after_header_len) - }) - .map_err(|e| { - // if anything went wrong, truncate any partial writes (e.g. just the header) - self.section.truncate(orig_len); - e - })?; - - if content_len != usize::from(de_header.len.as_u8()) { - panic!( - "Buggy WriteDataElement impl: header len {}, actual written len {}", - de_header.len.as_u8(), - content_len - ); - } - - self.next_de_offset = self.next_de_offset.incremented(); - - Ok(()) - } - - /// Add a data element to the section with a closure that returns the data element directly. - /// - /// The provided `build_de` closure will be invoked with the derived salt for this DE. - pub fn add_de<W: WriteDataElement, F: FnOnce(SE::DerivedSalt) -> W>( - &mut self, - build_de: F, - ) -> Result<(), AddDataElementError<()>> { - self.add_de_res(|derived_salt| Ok::<_, ()>(build_de(derived_salt))) - } - - /// Convert a section builder's contents into an encoded section. - /// - /// Implemented without self to avoid partial-move issues. - fn build_section( - adv_builder_header_byte: u8, - mut section_contents: tinyvec::ArrayVec<[u8; NP_ADV_MAX_SECTION_LEN]>, - mut section_encoder: SE, - ) -> EncodedSection { - // there is space because the capacity for DEs was restricted to allow it - section_contents.resize(section_contents.len() + SE::SUFFIX_LEN, 0); - - section_contents[0] = section_contents - .len() - .try_into() - .ok() - .and_then(|len: u8| len.checked_sub(1)) - .expect("section length is always <=255 and non-negative"); - - section_encoder.postprocess( - adv_builder_header_byte, - section_contents[0], - &mut section_contents[1..], - ); - - to_array_view(section_contents) - } -} - -/// Errors for adding a DE to a section -#[derive(Debug, PartialEq, Eq)] -pub enum AddDataElementError<E> { - /// An error occurred when invoking the DE builder closure. - BuildDeError(E), - /// Too much data to fit into the section - InsufficientSectionSpace, -} - /// The advertisement type, which dictates what sections can exist #[derive(Debug, PartialEq, Eq)] pub enum AdvertisementType { @@ -483,288 +325,18 @@ } } -/// Everything needed to properly encode a section -pub trait SectionEncoder { - /// How much space needs to be reserved for this identity's prefix bytes after the section - /// header and before other DEs - const PREFIX_LEN: usize; - - /// How much space needs to be reserved after the DEs - const SUFFIX_LEN: usize; - - /// The DE offset to use for any DEs added to the section - const INITIAL_DE_OFFSET: DataElementOffset; - - /// The advertisement type that can support this section - const ADVERTISEMENT_TYPE: AdvertisementType; - - /// Postprocess the contents of the section (the data after the section header byte), which will - /// start with [Self::PREFIX_LEN] bytes set aside for the identity's use, and similarly end with - /// [Self::SUFFIX_LEN] bytes, with DEs (if any) in the middle. - fn postprocess(&mut self, adv_header_byte: u8, section_header: u8, section_contents: &mut [u8]); - - /// The type of derived salt produced for a DE sharing a section with this identity. - type DerivedSalt; - - /// Produce a `Self::Output` salt for a DE. - fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt; -} - -/// Public section for plaintext data elements -#[derive(Default, Debug)] -pub struct PublicSectionEncoder {} -impl SectionEncoder for PublicSectionEncoder { - /// 1 byte of public identity DE header - const PREFIX_LEN: usize = 1; - const SUFFIX_LEN: usize = 0; - /// Room for the public DE - const INITIAL_DE_OFFSET: DataElementOffset = DataElementOffset::ZERO.incremented(); - const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Plaintext; - fn postprocess( - &mut self, - _adv_header_byte: u8, - _section_header: u8, - section_contents: &mut [u8], - ) { - section_contents[0..1].copy_from_slice( - DeHeader { len: DeLength::ZERO, de_type: IdentityDataElementType::Public.type_code() } - .serialize() - .as_slice(), - ) - } - type DerivedSalt = (); - fn de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt {} -} - -/// Encrypts the data elements and protects integrity with an np_ed25519 signature -/// using key material derived from an NP identity. -pub struct SignedEncryptedSectionEncoder<C: CryptoProvider> { - identity_type: EncryptedIdentityDataElementType, - salt: RawV1Salt, - metadata_key: MetadataKey, - key_pair: np_ed25519::KeyPair<C>, - aes_key: Aes128Key, -} - -impl<C: CryptoProvider> SignedEncryptedSectionEncoder<C> { - /// Build a [SignedEncryptedSectionEncoder] from an identity type, - /// some broadcast crypto-material, and with a random salt. - pub fn new_random_salt<B: SignedBroadcastCryptoMaterial>( - rng: &mut C::CryptoRng, - identity_type: EncryptedIdentityDataElementType, - crypto_material: &B, - ) -> Self { - let salt = RawV1Salt(rng.gen::<[u8; 16]>()); - Self::new(identity_type, salt, crypto_material) - } - - /// Build a [SignedEncryptedSectionEncoder] from an identity type, - /// a provided salt, and some broadcast crypto-material. - pub(crate) fn new<B: SignedBroadcastCryptoMaterial>( - identity_type: EncryptedIdentityDataElementType, - salt: RawV1Salt, - crypto_material: &B, - ) -> Self { - let metadata_key = crypto_material.metadata_key(); - let key_seed = crypto_material.key_seed(); - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); - let private_key = crypto_material.signing_key(); - let key_pair = np_ed25519::KeyPair::<C>::from_private_key(&private_key); - let aes_key = key_seed_hkdf.extended_signed_section_aes_key(); - Self { identity_type, salt, metadata_key, key_pair, aes_key } - } -} - -impl<C: CryptoProvider> SectionEncoder for SignedEncryptedSectionEncoder<C> { - const PREFIX_LEN: usize = - EncryptionInfo::TOTAL_DE_LEN + EncryptedIdentityMetadata::TOTAL_DE_LEN; - /// Ed25519 signature - const SUFFIX_LEN: usize = crypto_provider::ed25519::SIGNATURE_LENGTH; - /// Room for the encryption info and identity DEs - const INITIAL_DE_OFFSET: DataElementOffset = - DataElementOffset::ZERO.incremented().incremented(); - const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted; - - fn postprocess( - &mut self, - adv_header_byte: u8, - section_header: u8, - section_contents: &mut [u8], - ) { - let encryption_info_bytes = EncryptionInfoDataElement::signature(&self.salt.0).serialize(); - section_contents[0..19].copy_from_slice(&encryption_info_bytes); - - let identity_header = identity_de_header(self.identity_type, self.metadata_key); - section_contents[19..21].copy_from_slice(identity_header.serialize().as_slice()); - section_contents[21..37].copy_from_slice(&self.metadata_key.0); - - let nonce: AesCtrNonce = self - .de_salt(v1_salt::DataElementOffset::from(1)) - .derive() - .expect("AES-CTR nonce is a valid HKDF length"); - - let (before_sig, sig) = - section_contents.split_at_mut(section_contents.len() - Self::SUFFIX_LEN); - let (encryption_info, after_encryption_info) = - before_sig.split_at(EncryptionInfo::TOTAL_DE_LEN); - - let encryption_info: &[u8; EncryptionInfo::TOTAL_DE_LEN] = - encryption_info.try_into().expect("encryption info should always be the correct size"); - - // we need to sign the 16-byte IV, which doesn't have to actually fit in the adv, but we - // don't need a bigger buffer here since we won't be including the 66 bytes for the sig + - // header. - // If the stack usage ever becomes a problem, we can investigate pre hashing for the - // signature. - let nonce_ref = &nonce; - let section_signature_payload = SectionSignaturePayload::from_serialized_parts( - adv_header_byte, - section_header, - encryption_info, - nonce_ref, - after_encryption_info, - ); - - let signature = section_signature_payload.sign(&self.key_pair); - - sig[0..64].copy_from_slice(&signature.to_bytes()); - - let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce)); - - // encrypt just the part that should be ciphertext: identity DE contents and subsequent DEs - cipher.apply_keystream(&mut section_contents[21..]); - } - - type DerivedSalt = DeSalt<C>; - - fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { - DeSalt { salt: V1Salt::from(self.salt.0), de_offset } - } -} - -/// Encrypts the data elements and protects integrity with a MIC using key material derived from -/// an NP identity. -pub struct MicEncryptedSectionEncoder<C: CryptoProvider> { - identity_type: EncryptedIdentityDataElementType, - salt: RawV1Salt, - metadata_key: MetadataKey, - aes_key: Aes128Key, - mic_hmac_key: np_hkdf::NpHmacSha256Key<C>, -} - -impl<C: CryptoProvider> MicEncryptedSectionEncoder<C> { - /// Build a [MicEncryptedSectionEncoder] from the provided identity - /// info with a random salt. - pub fn new_random_salt<B: BroadcastCryptoMaterial<V1>>( - rng: &mut C::CryptoRng, - identity_type: EncryptedIdentityDataElementType, - crypto_material: &B, - ) -> Self { - let salt = RawV1Salt(rng.gen::<[u8; 16]>()); - Self::new(identity_type, salt, crypto_material) - } - - /// Build a [MicEncryptedSectionEncoder] from the provided identity info. - pub(crate) fn new<B: BroadcastCryptoMaterial<V1>>( - identity_type: EncryptedIdentityDataElementType, - salt: RawV1Salt, - crypto_material: &B, - ) -> Self { - let metadata_key = crypto_material.metadata_key(); - let key_seed = crypto_material.key_seed(); - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); - let aes_key = np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf); - let mic_hmac_key = np_hkdf::UnsignedSectionKeys::hmac_key(&key_seed_hkdf); - - Self { identity_type, salt, metadata_key, aes_key, mic_hmac_key } - } - - /// Build a [MicEncrypedSectionEncoder] from the provided identity info. - /// Exposed outside of this crate for testing purposes only, since this - /// does not handle the generation of random salts. - #[cfg(any(test, feature = "testing"))] - pub fn new_for_testing<B: BroadcastCryptoMaterial<V1>>( - identity_type: EncryptedIdentityDataElementType, - salt: RawV1Salt, - crypto_material: &B, - ) -> Self { - Self::new(identity_type, salt, crypto_material) - } -} - -impl<C: CryptoProvider> SectionEncoder for MicEncryptedSectionEncoder<C> { - const PREFIX_LEN: usize = - EncryptionInfo::TOTAL_DE_LEN + EncryptedIdentityMetadata::TOTAL_DE_LEN; - /// Length of mic - const SUFFIX_LEN: usize = SectionMic::CONTENTS_LEN; - /// Room for the mic, encryption info, and identity DEs - const INITIAL_DE_OFFSET: DataElementOffset = - DataElementOffset::ZERO.incremented().incremented(); - - const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted; - - fn postprocess( - &mut self, - adv_header_byte: u8, - section_header: u8, - section_contents: &mut [u8], - ) { - // prefix byte layout: - // 0-18: Encryption Info DE (header + scheme + salt) - // 19-20: Identity DE header - // 21-36: Identity DE contents (metadata key) - // Encryption Info DE - let encryption_info_bytes = EncryptionInfoDataElement::mic(&self.salt.0).serialize(); - section_contents[0..19].copy_from_slice(&encryption_info_bytes); - // Identity DE - let identity_header = identity_de_header(self.identity_type, self.metadata_key); - section_contents[19..21].copy_from_slice(identity_header.serialize().as_slice()); - section_contents[21..37].copy_from_slice(&self.metadata_key.0); - // DE offset for identity is 1: Encryption Info DE, Identity DE, then other DEs - let nonce: AesCtrNonce = self - .de_salt(v1_salt::DataElementOffset::from(1)) - .derive() - .expect("AES-CTR nonce is a valid HKDF length"); - let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce)); - let ciphertext_end = section_contents.len() - SectionMic::CONTENTS_LEN; - // encrypt just the part that should be ciphertext: identity DE contents and subsequent DEs - cipher.apply_keystream(&mut section_contents[21..ciphertext_end]); - // calculate MAC per the spec - let mut section_hmac = self.mic_hmac_key.build_hmac(); - // svc uuid - section_hmac.update(NP_SVC_UUID.as_slice()); - // adv header - section_hmac.update(&[adv_header_byte]); - // section header - section_hmac.update(&[section_header]); - // encryption info - section_hmac.update(&encryption_info_bytes); - // derived salt - section_hmac.update(&nonce); - // identity header + ciphertext - section_hmac.update(§ion_contents[19..ciphertext_end]); - let mic: [u8; 32] = section_hmac.finalize(); - // write truncated MIC - section_contents[ciphertext_end..].copy_from_slice(&mic[..SectionMic::CONTENTS_LEN]); - } - type DerivedSalt = DeSalt<C>; - fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { - DeSalt { salt: V1Salt::from(self.salt.0), de_offset } - } -} - /// Derived salt for an individual data element. -pub struct DeSalt<C: CryptoProvider> { - salt: V1Salt<C>, +pub struct DeSalt { + salt: ExtendedV1Salt, de_offset: DataElementOffset, } -impl<C: CryptoProvider> DeSalt<C> { +impl DeSalt { /// Derive salt of the requested length. /// /// The length must be a valid HKDF-SHA256 length. - pub fn derive<const N: usize>(&self) -> Option<[u8; N]> { - self.salt.derive(Some(self.de_offset)) + pub fn derive<const N: usize, C: CryptoProvider>(&self) -> Option<[u8; N]> { + self.salt.derive::<N, C>(Some(self.de_offset)) } } @@ -823,7 +395,7 @@ let de_type = self.de_type.as_u32(); let hi_bit = 0x80_u8; let len = self.len.len; - if len < 8 && de_type < 16 { + if !de_requires_extended_bit(de_type, len) { buffer[0] = len << 4 | de_type as u8; ArrayView::try_from_array(buffer, 1).expect("1 is a valid length") } else { @@ -867,22 +439,6 @@ } } -fn identity_de_header( - id_type: EncryptedIdentityDataElementType, - metadata_key: MetadataKey, -) -> DeHeader { - DeHeader { - de_type: id_type.type_code(), - len: metadata_key - .0 - .len() - .try_into() - .map_err(|_e| DeLengthOutOfRange) - .and_then(|len: u8| len.try_into()) - .expect("metadata key is a valid DE length"), - } -} - /// A wrapper around a fixed-size tinyvec that can have its capacity further constrained to handle /// dynamic size limits. #[derive(Debug)] @@ -893,7 +449,7 @@ <[T; N] as tinyvec::Array>::Item: fmt::Debug + Clone, { /// constraint on the occupied space in `vec`. - /// Invariant: `vec.len() <= constraint` and `vec.capacity() >= capacity`. + /// Invariant: `vec.len() <= capacity` and `vec.capacity() >= capacity`. capacity: usize, vec: tinyvec::ArrayVec<[T; N]>, } @@ -904,6 +460,15 @@ [T; N]: tinyvec::Array + fmt::Debug, <[T; N] as tinyvec::Array>::Item: fmt::Debug + Clone, { + /// Returns `None` if `capacity > N` + pub(crate) fn new(capacity: usize) -> Option<Self> { + if capacity <= N { + Some(Self { capacity, vec: tinyvec::ArrayVec::new() }) + } else { + None + } + } + pub(crate) fn len(&self) -> usize { self.vec.len() } @@ -916,7 +481,7 @@ self.vec.truncate(len); } - fn into_inner(self) -> tinyvec::ArrayVec<[T; N]> { + pub(crate) fn into_inner(self) -> tinyvec::ArrayVec<[T; N]> { self.vec } } @@ -946,24 +511,3 @@ } } } - -impl<T, const N: usize> AsRef<[<[T; N] as tinyvec::Array>::Item]> for CapacityLimitedVec<T, N> -where - T: fmt::Debug + Clone, - [T; N]: tinyvec::Array + fmt::Debug, - <[T; N] as tinyvec::Array>::Item: fmt::Debug + Clone, -{ - fn as_ref(&self) -> &[<[T; N] as tinyvec::Array>::Item] { - self.vec.as_slice() - } -} -impl<T, const N: usize> AsMut<[<[T; N] as tinyvec::Array>::Item]> for CapacityLimitedVec<T, N> -where - T: fmt::Debug + Clone, - [T; N]: tinyvec::Array + fmt::Debug, - <[T; N] as tinyvec::Array>::Item: fmt::Debug + Clone, -{ - fn as_mut(&mut self) -> &mut [<[T; N] as tinyvec::Array>::Item] { - self.vec.as_mut_slice() - } -}
diff --git a/nearby/presence/np_adv/src/extended/serialize/section/encoder.rs b/nearby/presence/np_adv/src/extended/serialize/section/encoder.rs new file mode 100644 index 0000000..85f55bc --- /dev/null +++ b/nearby/presence/np_adv/src/extended/serialize/section/encoder.rs
@@ -0,0 +1,429 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::credential::v1::V1BroadcastCredential; +use crate::extended::salt::{MultiSalt, ShortV1Salt, V1Salt}; +use crate::header::VERSION_HEADER_V1; +use crate::{ + extended::{ + deserialize::SectionMic, + section_signature_payload::SectionSignaturePayload, + serialize::{section::header::SectionHeader, AdvertisementType, DeSalt}, + V1IdentityToken, V1_IDENTITY_TOKEN_LEN, + }, + NP_SVC_UUID, +}; +use crypto_provider::{ + aes, + aes::ctr::{AesCtr as _, AesCtrNonce, NonceAndCounter}, + ed25519, + hmac::Hmac, + CryptoProvider, CryptoRng as _, +}; +use np_hkdf::v1_salt::EXTENDED_SALT_LEN; +use np_hkdf::{ + v1_salt::{DataElementOffset, ExtendedV1Salt}, + DerivedSectionKeys, +}; + +/// Everything needed to properly encode a section +pub trait SectionEncoder { + /// How much space needs to be reserved after the DEs + const SUFFIX_LEN: usize; + + /// The advertisement type that can support this section + const ADVERTISEMENT_TYPE: AdvertisementType; + + /// The type of derived salt produced for a DE sharing a section with this identity. + type DerivedSalt; + + /// Header to write at the start of the section contents + fn header(&self) -> SectionHeader; + + /// Postprocess the contents of the section (the data after the section header byte), which will + /// start with the contents of [Self::header()], and similarly end with + /// [Self::SUFFIX_LEN] bytes, with DEs (if any) in the middle. + /// + /// `section_header_without_length` is the bytes of the section header up until but not + /// including the length byte + /// `section_len` is the length of the contents that come after the length byte which includes + /// the de contents + the suffix. This is the length of `remaining_content_bytes` stored as an u8 + /// `remaining_content_bytes` are the bytes of the rest of the contents that come after section length + fn postprocess<C: CryptoProvider>( + &mut self, + section_header_without_length: &mut [u8], + section_len: u8, + remaining_content_bytes: &mut [u8], + ); + + /// Produce a `Self::Output` salt for a DE. + fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt; +} + +/// Encoder for plaintext data elements +#[derive(Debug)] +pub struct UnencryptedSectionEncoder; + +impl UnencryptedSectionEncoder {} + +impl SectionEncoder for UnencryptedSectionEncoder { + const SUFFIX_LEN: usize = 0; + const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Plaintext; + + type DerivedSalt = (); + + fn header(&self) -> SectionHeader { + SectionHeader::unencrypted() + } + fn postprocess<C: CryptoProvider>( + &mut self, + _section_header_without_length: &mut [u8], + _section_len: u8, + _remaining_content_bytes: &mut [u8], + ) { + // no op + } + + fn de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt {} +} + +/// Encrypts the data elements and protects integrity with an np_ed25519 signature +/// using key material derived from an NP identity. +pub struct SignedEncryptedSectionEncoder { + pub(crate) salt: ExtendedV1Salt, + identity_token: V1IdentityToken, + private_key: ed25519::PrivateKey, + aes_key: aes::Aes128Key, +} + +impl SignedEncryptedSectionEncoder { + /// Build a [SignedEncryptedSectionEncoder] from an identity type, + /// some broadcast crypto-material, and with a random salt. + pub fn new_random_salt<C: CryptoProvider>( + rng: &mut C::CryptoRng, + crypto_material: &V1BroadcastCredential, + ) -> Self { + let salt: ExtendedV1Salt = rng.gen::<[u8; 16]>().into(); + Self::new::<C>(salt, crypto_material) + } + + /// Build a [SignedEncryptedSectionEncoder] from an identity type, + /// a provided salt, and some broadcast crypto-material. + pub(crate) fn new<C: CryptoProvider>( + salt: ExtendedV1Salt, + crypto_material: &V1BroadcastCredential, + ) -> Self { + let identity_token = crypto_material.identity_token(); + let key_seed = crypto_material.key_seed(); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); + let private_key = crypto_material.signing_key(); + let aes_key = key_seed_hkdf.v1_signature_keys().aes_key(); + Self { salt, identity_token, private_key, aes_key } + } +} + +impl SectionEncoder for SignedEncryptedSectionEncoder { + /// Ed25519 signature + const SUFFIX_LEN: usize = crypto_provider::ed25519::SIGNATURE_LENGTH; + const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted; + + type DerivedSalt = DeSalt; + + fn header(&self) -> SectionHeader { + SectionHeader::encrypted_signature_extended_salt(&self.salt, &self.identity_token) + } + + fn postprocess<C: CryptoProvider>( + &mut self, + section_header_without_length: &mut [u8], + section_len: u8, + remaining_contents: &mut [u8], + ) { + let nonce: AesCtrNonce = self.salt.compute_nonce::<C>(); + let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce)); + + let start_of_identity_token = section_header_without_length.len() - V1_IDENTITY_TOKEN_LEN; + let (format_and_salt_bytes, identity_token) = + section_header_without_length.split_at_mut(start_of_identity_token); + debug_assert!(identity_token.len() == V1_IDENTITY_TOKEN_LEN); + + let start_of_salt = format_and_salt_bytes.len() - EXTENDED_SALT_LEN; + let (format_bytes, salt_bytes) = format_and_salt_bytes.split_at_mut(start_of_salt); + debug_assert!(salt_bytes.len() == EXTENDED_SALT_LEN); + debug_assert!((1..=2).contains(&format_bytes.len())); + + let start_of_signature = remaining_contents.len() - Self::SUFFIX_LEN; + let (plaintext_data_elements, sig) = remaining_contents.split_at_mut(start_of_signature); + debug_assert!(sig.len() == Self::SUFFIX_LEN); + + let section_signature_payload = SectionSignaturePayload::new( + format_bytes, + salt_bytes, + &nonce, + identity_token, + section_len, + plaintext_data_elements, + ); + + sig.copy_from_slice( + §ion_signature_payload.sign::<C::Ed25519>(&self.private_key).to_bytes(), + ); + + cipher.apply_keystream(identity_token); + cipher.apply_keystream(plaintext_data_elements); + cipher.apply_keystream(sig); + } + + fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { + DeSalt { salt: self.salt, de_offset } + } +} + +/// Encrypts the data elements and protects integrity with a MIC using key material derived from +/// an NP identity. +pub struct MicEncryptedSectionEncoder<S> { + pub(crate) salt: S, + identity_token: V1IdentityToken, + aes_key: aes::Aes128Key, + mic_hmac_key: np_hkdf::NpHmacSha256Key, +} + +impl<S: MicSectionEncoderSalt> MicEncryptedSectionEncoder<S> { + /// Build a [MicEncryptedSectionEncoder] from the provided identity info. + pub(crate) fn new<C: CryptoProvider>( + salt: S, + broadcast_credential: &V1BroadcastCredential, + ) -> Self { + let identity_token = broadcast_credential.identity_token(); + let key_seed = broadcast_credential.key_seed(); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); + let aes_key = salt.derive_aes_key(&key_seed_hkdf); + let mic_hmac_key = salt.derive_mic_hmac_key(&key_seed_hkdf); + + Self { salt, identity_token, aes_key, mic_hmac_key } + } + + /// Build a [MicEncryptedSectionEncoder] from the provided identity info. + /// Exposed outside of this crate for testing purposes only, since this + /// does not handle the generation of random salts. + #[cfg(any(test, feature = "testing", feature = "devtools"))] + pub fn new_with_salt<C: CryptoProvider>( + salt: S, + broadcast_credential: &V1BroadcastCredential, + ) -> Self { + Self::new::<C>(salt, broadcast_credential) + } +} + +impl MicEncryptedSectionEncoder<ExtendedV1Salt> { + /// Build a [MicEncryptedSectionEncoder] from the provided identity + /// info with a random extended salt. + pub fn new_random_salt<C: CryptoProvider>( + rng: &mut C::CryptoRng, + broadcast_credential: &V1BroadcastCredential, + ) -> Self { + Self::new::<C>(rng.gen(), broadcast_credential) + } +} + +impl MicEncryptedSectionEncoder<MultiSalt> { + /// Build a [MicEncryptedSectionEncoder] from the provided identity + /// info with a random extended salt wrapped in [MultiSalt]. + /// + /// Prefer [Self::new_random_salt] unless there is a need for the type + /// parameter to be [MultiSalt]. + pub fn new_wrapped_salt<C: CryptoProvider>( + rng: &mut C::CryptoRng, + broadcast_credential: &V1BroadcastCredential, + ) -> Self { + Self::new::<C>(rng.gen::<ExtendedV1Salt>().into(), broadcast_credential) + } +} + +impl<S: MicSectionEncoderSalt> SectionEncoder for MicEncryptedSectionEncoder<S> { + /// Length of mic + const SUFFIX_LEN: usize = SectionMic::CONTENTS_LEN; + + const ADVERTISEMENT_TYPE: AdvertisementType = AdvertisementType::Encrypted; + + type DerivedSalt = S::DerivedSalt; + + fn header(&self) -> SectionHeader { + self.salt.header(&self.identity_token) + } + + fn postprocess<C: CryptoProvider>( + &mut self, + section_header_without_length: &mut [u8], + section_len: u8, + remaining_contents: &mut [u8], + ) { + let nonce: AesCtrNonce = self.salt.compute_nonce::<C>(); + let mut cipher = C::AesCtr128::new(&self.aes_key, NonceAndCounter::from_nonce(nonce)); + + let start_of_identity_token = section_header_without_length.len() - V1_IDENTITY_TOKEN_LEN; + let (format_and_salt_bytes, identity_token) = + section_header_without_length.split_at_mut(start_of_identity_token); + debug_assert!(identity_token.len() == V1_IDENTITY_TOKEN_LEN); + // format can be 1-2 bytes + debug_assert!((1 + self.salt.into().as_slice().len() + ..=2 + self.salt.into().as_slice().len()) + .contains(&format_and_salt_bytes.len())); + + let start_of_mic = remaining_contents.len() - Self::SUFFIX_LEN; + let (data_element_contents, mic) = remaining_contents.split_at_mut(start_of_mic); + debug_assert!(mic.len() == Self::SUFFIX_LEN); + + // First encrypt the identity token + cipher.apply_keystream(identity_token); + + // Now encrypt the rest of the ciphertext bytes that come after the section length byte + cipher.apply_keystream(data_element_contents); + + // calculate MAC per the spec + let mut section_hmac = self.mic_hmac_key.build_hmac::<C>(); + // svc uuid + section_hmac.update(NP_SVC_UUID.as_slice()); + // adv header + section_hmac.update(&[VERSION_HEADER_V1]); + // section format and salt + section_hmac.update(format_and_salt_bytes); + // nonce + section_hmac.update(&nonce); + // encrypted identity token + section_hmac.update(identity_token); + // section len + section_hmac.update(&[section_len]); + // rest of the ciphertext + section_hmac.update(data_element_contents); + + // write truncated MIC + mic.copy_from_slice(§ion_hmac.finalize()[..SectionMic::CONTENTS_LEN]); + } + + fn de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { + self.salt.derive_de_salt(de_offset) + } +} + +/// Behavior for salts used with MIC sections. +pub trait MicSectionEncoderSalt: V1Salt { + /// The type of derived data produced, or `()` if no data can be derived. + type DerivedSalt; + + /// Build the appropriate header for the type of salt used + fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader; + + /// Derive a DE salt at the specified offset. + fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt; + + /// Derive the AES key suitable for this salt type + fn derive_aes_key<C: CryptoProvider>(&self, hkdf: &np_hkdf::NpKeySeedHkdf<C>) + -> aes::Aes128Key; + + /// Derive the MIC HMAC key suitable for this salt type + fn derive_mic_hmac_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> np_hkdf::NpHmacSha256Key; +} + +impl MicSectionEncoderSalt for ExtendedV1Salt { + type DerivedSalt = DeSalt; + + fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader { + SectionHeader::encrypted_mic_extended_salt(self, identity_token) + } + + fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { + DeSalt { salt: *self, de_offset } + } + + fn derive_aes_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> aes::Aes128Key { + hkdf.v1_mic_extended_salt_keys().aes_key() + } + + fn derive_mic_hmac_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> np_hkdf::NpHmacSha256Key { + hkdf.v1_mic_extended_salt_keys().mic_hmac_key() + } +} + +// TODO is this impl used? +impl MicSectionEncoderSalt for ShortV1Salt { + type DerivedSalt = (); + + fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader { + SectionHeader::encrypted_mic_short_salt(*self, identity_token) + } + + fn derive_de_salt(&self, _de_offset: DataElementOffset) -> Self::DerivedSalt {} + + fn derive_aes_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> aes::Aes128Key { + hkdf.v1_mic_short_salt_keys().aes_key() + } + + fn derive_mic_hmac_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> np_hkdf::NpHmacSha256Key { + hkdf.v1_mic_short_salt_keys().mic_hmac_key() + } +} + +impl MicSectionEncoderSalt for MultiSalt { + type DerivedSalt = Option<DeSalt>; + + fn header(&self, identity_token: &V1IdentityToken) -> SectionHeader { + match self { + MultiSalt::Short(s) => SectionHeader::encrypted_mic_short_salt(*s, identity_token), + MultiSalt::Extended(s) => SectionHeader::encrypted_mic_extended_salt(s, identity_token), + } + } + + fn derive_de_salt(&self, de_offset: DataElementOffset) -> Self::DerivedSalt { + match self { + MultiSalt::Short(_) => None, + MultiSalt::Extended(s) => Some(DeSalt { salt: *s, de_offset }), + } + } + + fn derive_aes_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> aes::Aes128Key { + match self { + MultiSalt::Short(_) => hkdf.v1_mic_short_salt_keys().aes_key(), + MultiSalt::Extended(_) => hkdf.v1_mic_extended_salt_keys().aes_key(), + } + } + + fn derive_mic_hmac_key<C: CryptoProvider>( + &self, + hkdf: &np_hkdf::NpKeySeedHkdf<C>, + ) -> np_hkdf::NpHmacSha256Key { + match self { + MultiSalt::Short(_) => hkdf.v1_mic_short_salt_keys().mic_hmac_key(), + MultiSalt::Extended(_) => hkdf.v1_mic_extended_salt_keys().mic_hmac_key(), + } + } +}
diff --git a/nearby/presence/np_adv/src/extended/serialize/section/header.rs b/nearby/presence/np_adv/src/extended/serialize/section/header.rs new file mode 100644 index 0000000..5e8b2e4 --- /dev/null +++ b/nearby/presence/np_adv/src/extended/serialize/section/header.rs
@@ -0,0 +1,164 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::extended::salt::ShortV1Salt; +use crate::extended::{ + V1IdentityToken, V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, V1_ENCODING_UNENCRYPTED, +}; +use np_hkdf::v1_salt::ExtendedV1Salt; + +/// Format || salt || token +pub(crate) const SECTION_HEADER_MAX_LEN: usize = 2 + 16 + 16; + +/// Assembles the header bytes for a section after the section length, before postprocessing by +/// a [SectionEncoder](crate::extended::serialize::section::SectionEncoder). +/// +/// Does not include the overall NP header byte that defines the adv version. +pub struct SectionHeader { + /// The section header + /// Invariant: always has at least 1 byte + header_bytes: tinyvec::ArrayVec<[u8; SECTION_HEADER_MAX_LEN]>, +} + +impl SectionHeader { + pub(crate) fn unencrypted() -> Self { + let mut header_bytes = tinyvec::ArrayVec::new(); + header_bytes.push(V1_ENCODING_UNENCRYPTED); + Self { header_bytes } + } + + pub(crate) fn encrypted_mic_short_salt(salt: ShortV1Salt, token: &V1IdentityToken) -> Self { + let mut header_bytes = tinyvec::ArrayVec::new(); + header_bytes.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN); + header_bytes.extend_from_slice(salt.bytes().as_slice()); + header_bytes.extend_from_slice(token.bytes().as_slice()); + Self { header_bytes } + } + + pub(crate) fn encrypted_mic_extended_salt( + salt: &ExtendedV1Salt, + token: &V1IdentityToken, + ) -> Self { + let mut header_bytes = tinyvec::ArrayVec::new(); + header_bytes.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + header_bytes.extend_from_slice(salt.bytes().as_slice()); + header_bytes.extend_from_slice(token.bytes().as_slice()); + Self { header_bytes } + } + + pub(crate) fn encrypted_signature_extended_salt( + salt: &ExtendedV1Salt, + token: &V1IdentityToken, + ) -> Self { + let mut header_bytes = tinyvec::ArrayVec::new(); + header_bytes.push(V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN); + header_bytes.extend_from_slice(salt.bytes().as_slice()); + header_bytes.extend_from_slice(token.bytes().as_slice()); + Self { header_bytes } + } + + pub(crate) fn as_slice(&self) -> &[u8] { + self.header_bytes.as_slice() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::extended::V1_IDENTITY_TOKEN_LEN; + use ldt_np_adv::V0_SALT_LEN; + use np_hkdf::v1_salt::EXTENDED_SALT_LEN; + + const SHORT_SALT_BYTES: [u8; V0_SALT_LEN] = [0x10, 0x11]; + const EXTENDED_SALT_BYTES: [u8; EXTENDED_SALT_LEN] = [ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, + ]; + const TOKEN_BYTES: [u8; V1_IDENTITY_TOKEN_LEN] = [ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, + ]; + + #[test] + fn unencrypted_slice() { + assert_eq!(&[V1_ENCODING_UNENCRYPTED], SectionHeader::unencrypted().as_slice()); + } + + #[rustfmt::skip] + #[test] + fn encrypted_mic_short_salt_slice() { + assert_eq!( + &[ + // format + 0x01, + // salt + 0x10, 0x11, + // token + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, + 0x2C, 0x2D, 0x2E, 0x2F, + ], + SectionHeader::encrypted_mic_short_salt( + SHORT_SALT_BYTES.into(), + &TOKEN_BYTES.into() + ) + .as_slice() + ); + } + + #[rustfmt::skip] + #[test] + fn encrypted_mic_extended_salt_slice() { + assert_eq!( + &[ + // format + 0x02, + // salt + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + // token + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, + 0x2C, 0x2D, 0x2E, 0x2F, + ], + SectionHeader::encrypted_mic_extended_salt( + &EXTENDED_SALT_BYTES.into(), + &TOKEN_BYTES.into() + ) + .as_slice() + ); + } + + #[rustfmt::skip] + #[test] + fn encrypted_sig_extended_salt_slice() { + assert_eq!( + &[ + // format + 0x03, + // salt + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, + // token + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, + 0x2C, 0x2D, 0x2E, 0x2F, + ], + SectionHeader::encrypted_signature_extended_salt( + &EXTENDED_SALT_BYTES.into(), + &TOKEN_BYTES.into() + ) + .as_slice() + ); + } +}
diff --git a/nearby/presence/np_adv/src/extended/serialize/section/mod.rs b/nearby/presence/np_adv/src/extended/serialize/section/mod.rs new file mode 100644 index 0000000..8fb76ab --- /dev/null +++ b/nearby/presence/np_adv/src/extended/serialize/section/mod.rs
@@ -0,0 +1,204 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use array_view::ArrayView; +use crypto_provider::CryptoProvider; +use np_hkdf::v1_salt::DataElementOffset; +use sink::Sink as _; + +use crate::extended::{ + serialize::{ + section::encoder::SectionEncoder, AdvBuilder, CapacityLimitedVec, WriteDataElement, + }, + to_array_view, NP_ADV_MAX_SECTION_LEN, +}; + +pub(crate) mod encoder; +pub(crate) mod header; + +/// Accumulates data elements and encodes them into a section. +#[derive(Debug)] +pub struct SectionBuilder<R: AsMut<AdvBuilder>, SE: SectionEncoder> { + /// The length of the header produced by `section_encoder` + pub(crate) header_len: usize, + /// Contains the section header, the identity-specified overhead, and any DEs added + pub(crate) section: CapacityLimitedVec<u8, { NP_ADV_MAX_SECTION_LEN }>, + pub(crate) section_encoder: SE, + /// mut ref-able to enforce only one active section builder at a time + pub(crate) adv_builder: R, + next_de_offset: DataElementOffset, +} + +impl<'a, SE: SectionEncoder> SectionBuilder<&'a mut AdvBuilder, SE> { + /// Add this builder to the advertisement that created it. + pub fn add_to_advertisement<C: CryptoProvider>(self) { + let _ = self.add_to_advertisement_internal::<C>(); + } +} + +impl<SE: SectionEncoder> SectionBuilder<AdvBuilder, SE> { + /// Gets the 0-based index of the section currently under construction + /// in the context of the containing advertisement. + pub fn section_index(&self) -> usize { + self.adv_builder.section_count() + } + /// Add this builder to the advertisement that created it, + /// and returns the containing advertisement back to the caller. + pub fn add_to_advertisement<C: CryptoProvider>(self) -> AdvBuilder { + self.add_to_advertisement_internal::<C>() + } +} + +impl<R: AsMut<AdvBuilder>, SE: SectionEncoder> SectionBuilder<R, SE> { + pub(crate) fn new( + header_len: usize, + section: CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>, + section_encoder: SE, + adv_builder: R, + ) -> Self { + Self { + header_len, + section, + section_encoder, + adv_builder, + next_de_offset: DataElementOffset::ZERO, + } + } + + /// Add this builder to the advertisement that created it. + /// Returns the mut-refable to the advertisement builder + /// which the contents of this section builder were added to. + //TODO: make this fallible, if the section being added is invalid, right now it is possible to + // create invalid adv's that don't parse + fn add_to_advertisement_internal<C: CryptoProvider>(mut self) -> R { + let adv_builder = self.adv_builder.as_mut(); + adv_builder.add_section(Self::build_section::<C>( + self.header_len, + self.section.into_inner(), + self.section_encoder, + )); + self.adv_builder + } + + /// Gets the derived salt which will be employed for the next DE offset. + /// + /// Suitable for scenarios (like FFI) where a closure would be inappropriate + /// for DE construction, and interaction with the client is preferred. + pub fn next_de_salt(&self) -> SE::DerivedSalt { + self.section_encoder.de_salt(self.next_de_offset) + } + + /// Add a data element to the section with a closure that returns a `Result`. + /// + /// The provided `build_de` closure will be invoked with the derived salt for this DE. + pub fn add_de_res<W: WriteDataElement, E, F: FnOnce(SE::DerivedSalt) -> Result<W, E>>( + &mut self, + build_de: F, + ) -> Result<(), AddDataElementError<E>> { + let writer = build_de(self.next_de_salt()).map_err(AddDataElementError::BuildDeError)?; + + let orig_len = self.section.len(); + // since we own the writer, and it's immutable, no race risk writing header w/ len then + // the contents as long as it's not simply an incorrect impl + let de_header = writer.de_header(); + let content_len = self + .section + .try_extend_from_slice(de_header.serialize().as_slice()) + .ok_or(AddDataElementError::InsufficientSectionSpace) + .and_then(|_| { + let after_header_len = self.section.len(); + writer + .write_de_contents(&mut self.section) + .ok_or(AddDataElementError::InsufficientSectionSpace) + .map(|_| self.section.len() - after_header_len) + }) + .map_err(|e| { + // if anything went wrong, truncate any partial writes (e.g. just the header) + self.section.truncate(orig_len); + e + })?; + + if content_len != usize::from(de_header.len.as_u8()) { + // TODO eliminate this possibility by keeping a 127-byte buffer + // to write DEs into, then calculating the written length, so the + // DE impl doesn't have to do it + panic!( + "Buggy WriteDataElement impl: header len {}, actual written len {}", + de_header.len.as_u8(), + content_len + ); + } + + self.next_de_offset = self.next_de_offset.incremented(); + + Ok(()) + } + + /// Add a data element to the section with a closure that returns the data element directly. + /// + /// The provided `build_de` closure will be invoked with the derived salt for this DE. + pub fn add_de<W: WriteDataElement, F: FnOnce(SE::DerivedSalt) -> W>( + &mut self, + build_de: F, + ) -> Result<(), AddDataElementError<()>> { + self.add_de_res(|derived_salt| Ok::<_, ()>(build_de(derived_salt))) + } + + /// Convert a section builder's contents into an encoded section. + /// + /// `section_contents` must have size > 0. + /// + /// `header_len` is the length of the prefix of `section_contents` that has been populated + /// with the data returned from [SectionEncoder::header()] which does NOT include the length byte. + /// + /// Implemented without self to avoid partial-move issues. + pub(crate) fn build_section<C: CryptoProvider>( + header_len: usize, + mut section_contents: tinyvec::ArrayVec<[u8; NP_ADV_MAX_SECTION_LEN]>, + mut section_encoder: SE, + ) -> EncodedSection { + // there is space because the capacity for DEs was restricted to allow it + section_contents.resize(section_contents.len() + SE::SUFFIX_LEN, 0); + + let (format_and_salt_and_identity_token, rest_of_contents) = + section_contents.split_at_mut(header_len); + + let (section_length_byte, rest_of_contents) = rest_of_contents.split_at_mut(1); + + let section_len = rest_of_contents.len().try_into().expect( + "section length will always fit into a u8 and has been validated by the section builder", + ); + // set the section length byte + section_length_byte[0] = section_len; + section_encoder.postprocess::<C>( + format_and_salt_and_identity_token, + section_len, + rest_of_contents, + ); + + to_array_view(section_contents) + } +} + +/// Errors for adding a DE to a section +#[derive(Debug, PartialEq, Eq)] +pub enum AddDataElementError<E> { + /// An error occurred when invoking the DE builder closure. + BuildDeError(E), + /// Too much data to fit into the section + InsufficientSectionSpace, +} + +/// The encoded form of an advertisement section +pub(crate) type EncodedSection = ArrayView<u8, NP_ADV_MAX_SECTION_LEN>;
diff --git a/nearby/presence/np_adv/src/extended/serialize/section_tests.rs b/nearby/presence/np_adv/src/extended/serialize/section_tests.rs index 2961fec..e1e90b7 100644 --- a/nearby/presence/np_adv/src/extended/serialize/section_tests.rs +++ b/nearby/presence/np_adv/src/extended/serialize/section_tests.rs
@@ -17,28 +17,46 @@ extern crate std; use super::*; -use crate::credential::{ - v1::{SimpleSignedBroadcastCryptoMaterial, V1}, - SimpleBroadcastCryptoMaterial, +use crate::extended::{ + V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN, + V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, V1_ENCODING_UNENCRYPTED, }; -use crate::extended::data_elements::GenericDataElement; -use crate::extended::serialize::AddSectionError::MaxSectionCountExceeded; -use crypto_provider::aes::ctr::AES_CTR_NONCE_LEN; +use crate::{ + credential::v1::V1BroadcastCredential, + extended::{ + data_elements::{GenericDataElement, GenericDataElementError}, + deserialize::SectionMic, + salt::V1Salt, + section_signature_payload::SectionSignaturePayload, + serialize::AddSectionError::MaxSectionCountExceeded, + V1IdentityToken, V1_IDENTITY_TOKEN_LEN, + }, + NP_SVC_UUID, +}; +use crypto_provider::ed25519; +use crypto_provider::ed25519::SIGNATURE_LENGTH; +use crypto_provider::{ + aes::ctr::{AesCtr, NonceAndCounter}, + hmac::Hmac, + CryptoRng, +}; use crypto_provider_default::CryptoProviderImpl; -use np_hkdf::v1_salt::V1Salt; -use rand::rngs::StdRng; -use rand::{prelude::SliceRandom as _, Rng as _, SeedableRng as _}; +use np_hkdf::v1_salt::EXTENDED_SALT_LEN; +use np_hkdf::DerivedSectionKeys; +use rand::{rngs::StdRng, Rng as _, SeedableRng as _}; use std::{prelude::rust_2021::*, vec}; -use strum::IntoEnumIterator as _; -type KeyPair = np_ed25519::KeyPair<CryptoProviderImpl>; +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; #[test] -fn public_identity_section_empty() { +fn unencrypted_section_empty() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); - assert_eq!(&[1_u8, 0x03], section_builder.into_section().as_slice()); + assert_eq!( + &[V1_ENCODING_UNENCRYPTED, 0_u8], + section_builder.into_section::<CryptoProviderImpl>().as_slice() + ); } #[test] @@ -64,99 +82,81 @@ }) .collect::<Vec<_>>(); - let metadata_key = rng.gen(); - let metadata_key = MetadataKey(metadata_key); + let identity_token: V1IdentityToken = crypto_rng.gen(); let key_seed = rng.gen(); - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( - &mut crypto_rng, - identity_type, - &broadcast_cm, - )) - .unwrap(); - let section_salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let mut section_builder = + adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::< + CryptoProviderImpl, + >(&mut crypto_rng, &broadcast_cred)) + .unwrap(); + let section_salt = section_builder.section_encoder.salt; for de in extra_des.iter() { section_builder.add_de(|_| de).unwrap(); } - // length 53: 19 for encryption info, 18 for identity, 16 for MIC - let section_length = 53 - + extra_des - .iter() - .map(|de| de.de_header().serialize().len() as u8 + de.de_header().len.as_u8()) - .sum::<u8>(); + let section_length = mic_section_len(&extra_des); - let encryption_info = [ - &[ - 0x91, 0x10, // header - 0x00, // scheme (mic) - ], - section_salt.as_slice(), - ] - .concat(); + let mut hmac = key_seed_hkdf + .v1_mic_extended_salt_keys() + .mic_hmac_key() + .build_hmac::<CryptoProviderImpl>(); + let nonce = section_salt.compute_nonce::<CryptoProviderImpl>(); - let identity_de_header = - DeHeader { len: 16_u8.try_into().unwrap(), de_type: identity_type.type_code() }; + let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &key_seed_hkdf.v1_mic_extended_salt_keys().aes_key(), + NonceAndCounter::from_nonce(nonce), + ); - let mut hmac = np_hkdf::UnsignedSectionKeys::hmac_key(&key_seed_hkdf).build_hmac(); + // encrypt identity token and de contents + let mut plaintext_identity_token = identity_token.as_slice().to_vec(); + cipher.apply_keystream(&mut plaintext_identity_token); + let ct_identity_token = plaintext_identity_token; + + let mut de_contents = Vec::new(); + for de in extra_des { + de_contents.extend_from_slice(de.de_header().serialize().as_slice()); + let _ = de.write_de_contents(&mut de_contents); + } + cipher.apply_keystream(&mut de_contents); + // just to be sure, we'll construct our test hmac all in one update() call let mut hmac_input = vec![]; hmac_input.extend_from_slice(NP_SVC_UUID.as_slice()); - hmac_input.push(0b00100000); // v1 - - // section header - hmac_input.push(section_length); - hmac_input.extend_from_slice(&encryption_info); - let nonce = section_salt.derive::<{ AES_CTR_NONCE_LEN }>(Some(1.into())).unwrap(); + hmac_input.push(VERSION_HEADER_V1); + hmac_input.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + hmac_input.extend_from_slice(section_salt.as_slice()); hmac_input.extend_from_slice(nonce.as_slice()); - - hmac_input.extend_from_slice(identity_de_header.serialize().as_slice()); - - let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf), - NonceAndCounter::from_nonce(nonce), - ); - let mut plaintext = metadata_key.0.as_slice().to_vec(); - - for de in extra_des { - plaintext.extend_from_slice(de.de_header().serialize().as_slice()); - let _ = de.write_de_contents(&mut plaintext); - } - - cipher.apply_keystream(&mut plaintext); - let ciphertext = plaintext; - - hmac_input.extend_from_slice(&ciphertext); - + hmac_input.extend_from_slice(&ct_identity_token); + hmac_input.push(section_length); + hmac_input.extend_from_slice(&de_contents); hmac.update(&hmac_input); let mic = hmac.finalize(); let mut expected = vec![]; + expected.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + expected.extend_from_slice(section_salt.as_slice()); + expected.extend_from_slice(&ct_identity_token); expected.push(section_length); - expected.extend_from_slice(&encryption_info); - expected.extend_from_slice(identity_de_header.serialize().as_slice()); - expected.extend_from_slice(&ciphertext); + expected.extend_from_slice(&de_contents); expected.extend_from_slice(&mic[..16]); - assert_eq!(&expected, section_builder.into_section().as_slice()); + assert_eq!(&expected, section_builder.into_section::<CryptoProviderImpl>().as_slice()); } } #[test] -fn signature_encrypted_identity_section_empty() { - do_signature_encrypted_identity_fixed_key_material_test::<DummyDataElement>(&[]); -} - -#[test] fn signature_encrypted_identity_section_random_des() { let mut rng = StdRng::from_entropy(); let mut crypto_rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); @@ -164,29 +164,23 @@ for _ in 0..1_000 { let num_des = rng.gen_range(1..=5); - let metadata_key = MetadataKey(rng.gen()); + let identity_token = V1IdentityToken(rng.gen()); let key_seed = rng.gen(); - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let key_pair = KeyPair::generate(); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); - let broadcast_cm = SimpleSignedBroadcastCryptoMaterial::new( - key_seed, - metadata_key, - key_pair.private_key(), - ); + let broadcast_cred = + V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - identity_type, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); - let section_salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let section_salt = section_builder.section_encoder.salt; let extra_des = (0..num_des) .map(|_| { @@ -200,32 +194,8 @@ .filter_map(|de| section_builder.add_de(|_| de.clone()).ok().map(|_| de)) .collect::<Vec<_>>(); - // 19 for encryption info, 18 for identity, 64 for signature - let section_length = 19 - + 18 - + 64 - + extra_des - .iter() - .map(|de| de.de_header().serialize().len() as u8 + de.de_header().len.as_u8()) - .sum::<u8>(); - - let encryption_info = [ - &[ - 0x91, 0x10, // header - 0x08, // scheme (signature) - ], - section_salt.as_slice(), - ] - .concat(); - let encryption_info: [u8; EncryptionInfo::TOTAL_DE_LEN] = - encryption_info.try_into().unwrap(); - - let identity_de_header = - DeHeader { len: 16_u8.try_into().unwrap(), de_type: identity_type.type_code() }; - let identity_de_header: [u8; 2] = - identity_de_header.serialize().as_slice().try_into().unwrap(); - - let nonce = section_salt.derive::<{ AES_CTR_NONCE_LEN }>(Some(1.into())).unwrap(); + let section_length = sig_section_len(&extra_des); + let nonce = section_salt.compute_nonce::<CryptoProviderImpl>(); let mut section_body = Vec::new(); for de in extra_des { @@ -233,34 +203,41 @@ let _ = de.write_de_contents(&mut section_body); } - let sig_payload = SectionSignaturePayload::from_deserialized_parts( - 0x20, - section_length, - &encryption_info, + let mut section_header = vec![]; + section_header + .extend_from_slice(&[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN]); + section_header.extend_from_slice(section_salt.as_slice()); + section_header.extend_from_slice(identity_token.as_slice()); + + let sig_payload = SectionSignaturePayload::new( + &[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN], + section_salt.as_slice(), &nonce, - identity_de_header, - metadata_key, + identity_token.as_slice(), + section_length, §ion_body, ); - let mut plaintext = metadata_key.0.as_slice().to_vec(); - plaintext.extend_from_slice(section_body.as_slice()); + let mut plaintext = section_body.as_slice().to_vec(); + plaintext + .extend_from_slice(&sig_payload.sign::<Ed25519ProviderImpl>(&private_key).to_bytes()); - plaintext.extend_from_slice(&sig_payload.sign(&key_pair).to_bytes()); - - <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &key_seed_hkdf.extended_signed_section_aes_key(), + let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &key_seed_hkdf.v1_signature_keys().aes_key(), NonceAndCounter::from_nonce(nonce), - ) - .apply_keystream(&mut plaintext); + ); + let start_of_identity_token = section_header.len() - V1_IDENTITY_TOKEN_LEN; + cipher.apply_keystream(&mut section_header[start_of_identity_token..]); + + cipher.apply_keystream(&mut plaintext); let ciphertext = plaintext; - let mut expected = vec![section_length]; - expected.extend_from_slice(&encryption_info); - expected.extend_from_slice(&identity_de_header); + let mut expected = vec![]; + expected.extend_from_slice(§ion_header); + expected.push(section_length); expected.extend_from_slice(&ciphertext); - assert_eq!(&expected, section_builder.into_section().as_slice()); + assert_eq!(&expected, section_builder.into_section::<CryptoProviderImpl>().as_slice()); } } @@ -272,23 +249,26 @@ let key_seed = [22; 32]; let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key = MetadataKey([33; 16]); + let identity_token = V1IdentityToken([33; 16]); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Trusted, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); - let salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let salt = section_builder.section_encoder.salt; section_builder .add_de(|de_salt| DummyDataElement { de_type: 100_u32.into(), - data: de_salt.derive::<100>().unwrap().to_vec(), + data: de_salt.derive::<100, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); @@ -298,7 +278,7 @@ section_builder .add_de(|de_salt| DummyDataElement { de_type: 101_u32.into(), - data: de_salt.derive::<100>().unwrap().to_vec(), + data: de_salt.derive::<100, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap_err() ); @@ -306,35 +286,38 @@ section_builder .add_de(|de_salt| DummyDataElement { de_type: 102_u32.into(), - data: de_salt.derive::<10>().unwrap().to_vec(), + data: de_salt.derive::<10, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let mut expected = vec![]; - // metadata key - expected.extend_from_slice(&metadata_key.0); + // identity token + expected.extend_from_slice(&identity_token.0); + // section len + expected.push(2 + 100 + 2 + 10u8 + u8::try_from(SectionMic::CONTENTS_LEN).unwrap()); // de header expected.extend_from_slice(&[0x80 + 100, 100]); - // section 0 de 2 - expected.extend_from_slice(&salt.derive::<100>(Some(2.into())).unwrap()); + // section 0 de 0 + expected.extend_from_slice(&salt.derive::<100, CryptoProviderImpl>(Some(0.into())).unwrap()); // de header expected.extend_from_slice(&[0x80 + 10, 102]); - // section 0 de 3 - expected.extend_from_slice(&salt.derive::<10>(Some(3.into())).unwrap()); + // section 0 de 1 + expected.extend_from_slice(&salt.derive::<10, CryptoProviderImpl>(Some(1.into())).unwrap()); let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf), - NonceAndCounter::from_nonce(salt.derive(Some(1.into())).unwrap()), + &key_seed_hkdf.v1_mic_extended_salt_keys().aes_key(), + NonceAndCounter::from_nonce(salt.compute_nonce::<CryptoProviderImpl>()), ); - cipher.apply_keystream(&mut expected); + cipher.apply_keystream(&mut expected[..V1_IDENTITY_TOKEN_LEN]); + cipher.apply_keystream(&mut expected[V1_IDENTITY_TOKEN_LEN + 1..]); let adv_bytes = adv_builder.into_advertisement(); // ignoring the MIC, etc, since that's tested elsewhere - let ciphertext_end = adv_bytes.as_slice().len() - 16; - assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + 19 + 2..ciphertext_end]) + let ciphertext_end = adv_bytes.as_slice().len() - SectionMic::CONTENTS_LEN; + assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + EXTENDED_SALT_LEN..ciphertext_end]) } #[test] @@ -344,9 +327,10 @@ let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); // fill up space to produce desired capacity - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); - // leave space for adv header, 1 section headers, 1 section identity and fill almost full - fill_section_builder(BLE_ADV_SVC_CONTENT_LEN - 1 - 1 - 1 - 1, &mut section_builder); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); + // leave space for adv header, 1 section len, 1 section header and 1 extra byte + fill_section_builder(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 1 - 1 - 1 - 1, &mut section_builder) + .unwrap(); assert_eq!(1, section_builder.section.capacity() - section_builder.section.len(), "capacity: "); // can't add a 2 byte DE @@ -368,23 +352,26 @@ let key_seed = [22; 32]; let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key = MetadataKey([33; 16]); + let identity_token = V1IdentityToken([33; 16]); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Trusted, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); - let salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let salt = section_builder.section_encoder.salt; section_builder .add_de(|de_salt| DummyDataElement { de_type: 100_u32.into(), - data: de_salt.derive::<100>().unwrap().to_vec(), + data: de_salt.derive::<100, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); @@ -396,35 +383,38 @@ section_builder .add_de(|de_salt| DummyDataElement { de_type: 103_u32.into(), - data: de_salt.derive::<10>().unwrap().to_vec(), + data: de_salt.derive::<10, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let mut expected = vec![]; - // metadata key - expected.extend_from_slice(&metadata_key.0); + // identity_token + expected.extend_from_slice(identity_token.as_slice()); + //section len + expected.push(2 + 100 + 2 + 10 + u8::try_from(SectionMic::CONTENTS_LEN).unwrap()); // de header expected.extend_from_slice(&[0x80 + 100, 100]); - // section 0 de 2 - expected.extend_from_slice(&salt.derive::<100>(Some(2.into())).unwrap()); + // section 0 de 0 + expected.extend_from_slice(&salt.derive::<100, CryptoProviderImpl>(Some(0.into())).unwrap()); // de header expected.extend_from_slice(&[0x80 + 10, 103]); - // section 0 de 3 - expected.extend_from_slice(&salt.derive::<10>(Some(3.into())).unwrap()); + // section 0 de 1 + expected.extend_from_slice(&salt.derive::<10, CryptoProviderImpl>(Some(1.into())).unwrap()); let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf), - NonceAndCounter::from_nonce(salt.derive(Some(1.into())).unwrap()), + &key_seed_hkdf.v1_mic_extended_salt_keys().aes_key(), + NonceAndCounter::from_nonce(salt.compute_nonce::<CryptoProviderImpl>()), ); - cipher.apply_keystream(&mut expected); + cipher.apply_keystream(&mut expected[..V1_IDENTITY_TOKEN_LEN]); + cipher.apply_keystream(&mut expected[V1_IDENTITY_TOKEN_LEN + 1..]); let adv_bytes = adv_builder.into_advertisement(); // ignoring the MIC, etc, since that's tested elsewhere - let ciphertext_end = adv_bytes.as_slice().len() - 16; - assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + 19 + 2..ciphertext_end]) + let ciphertext_end = adv_bytes.as_slice().len() - SectionMic::CONTENTS_LEN; + assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + EXTENDED_SALT_LEN..ciphertext_end]) } #[test] @@ -435,57 +425,63 @@ let key_seed = [22; 32]; let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key = MetadataKey([33; 16]); + let identity_token = V1IdentityToken([33; 16]); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(MicEncryptedSectionEncoder::<_>::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Trusted, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); - let salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let salt = section_builder.section_encoder.salt; section_builder .add_de(|de_salt| DummyDataElement { de_type: 64_u32.into(), - data: de_salt.derive::<16>().unwrap().to_vec(), + data: de_salt.derive::<16, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); section_builder .add_de(|de_salt| DummyDataElement { de_type: 65_u32.into(), - data: de_salt.derive::<16>().unwrap().to_vec(), + data: de_salt.derive::<16, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let mut expected = vec![]; - // metadata key - expected.extend_from_slice(&metadata_key.0); + // identity_token + expected.extend_from_slice(identity_token.as_slice()); + // section len, 2 des of 18 bytes each + section mic length + expected.push((18 * 2u8) + u8::try_from(SectionMic::CONTENTS_LEN).unwrap()); // de header expected.extend_from_slice(&[0x90, 0x40]); - // section 0 de 2 - expected.extend_from_slice(&salt.derive::<16>(Some(2.into())).unwrap()); + // section 0 de 0 + expected.extend_from_slice(&salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap()); // de header expected.extend_from_slice(&[0x90, 0x41]); - // section 0 de 3 - expected.extend_from_slice(&salt.derive::<16>(Some(3.into())).unwrap()); + // section 0 de 1 + expected.extend_from_slice(&salt.derive::<16, CryptoProviderImpl>(Some(1.into())).unwrap()); let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf), - NonceAndCounter::from_nonce(salt.derive(Some(1.into())).unwrap()), + &key_seed_hkdf.v1_mic_extended_salt_keys().aes_key(), + NonceAndCounter::from_nonce(salt.derive::<12, CryptoProviderImpl>(None).unwrap()), ); - cipher.apply_keystream(&mut expected); + cipher.apply_keystream(&mut expected[..V1_IDENTITY_TOKEN_LEN]); + cipher.apply_keystream(&mut expected[V1_IDENTITY_TOKEN_LEN + 1..]); let adv_bytes = adv_builder.into_advertisement(); // ignoring the MIC, etc, since that's tested elsewhere let ciphertext_end = adv_bytes.as_slice().len() - 16; - assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + 19 + 2..ciphertext_end]) + assert_eq!(&expected, &adv_bytes.as_slice()[1 + 1 + 16..ciphertext_end]) } #[test] @@ -496,60 +492,62 @@ let key_seed = [22; 32]; let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key = MetadataKey([33; 16]); - let key_pair = KeyPair::generate(); + let identity_token = V1IdentityToken([33; 16]); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); + let broadcast_cred = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Trusted, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); - let salt: V1Salt<CryptoProviderImpl> = section_builder.section_encoder.salt.into(); + let salt = section_builder.section_encoder.salt; section_builder .add_de(|de_salt| DummyDataElement { de_type: 64_u32.into(), - data: de_salt.derive::<16>().unwrap().to_vec(), + data: de_salt.derive::<16, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); section_builder .add_de(|de_salt| DummyDataElement { de_type: 65_u32.into(), - data: de_salt.derive::<16>().unwrap().to_vec(), + data: de_salt.derive::<16, CryptoProviderImpl>().unwrap().to_vec(), }) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let mut expected = vec![]; - // metadata key - expected.extend_from_slice(&metadata_key.0); + // identity token + expected.extend_from_slice(&identity_token.0); + //len + expected.push((18 * 2) + u8::try_from(SIGNATURE_LENGTH).unwrap()); // de header expected.extend_from_slice(&[0x90, 0x40]); - // section 0 de 2 - expected.extend_from_slice(&salt.derive::<16>(Some(2.into())).unwrap()); + // section 0 de 0 + expected.extend_from_slice(&salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap()); // de header expected.extend_from_slice(&[0x90, 0x41]); - // section 0 de 3 - expected.extend_from_slice(&salt.derive::<16>(Some(3.into())).unwrap()); + // section 0 de 1 + expected.extend_from_slice(&salt.derive::<16, CryptoProviderImpl>(Some(1.into())).unwrap()); - <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &key_seed_hkdf.extended_signed_section_aes_key(), - NonceAndCounter::from_nonce(salt.derive(Some(1.into())).unwrap()), - ) - .apply_keystream(&mut expected); + let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &key_seed_hkdf.v1_signature_keys().aes_key(), + NonceAndCounter::from_nonce(salt.derive::<12, CryptoProviderImpl>(None).unwrap()), + ); + + cipher.apply_keystream(&mut expected[..V1_IDENTITY_TOKEN_LEN]); + cipher.apply_keystream(&mut expected[V1_IDENTITY_TOKEN_LEN + 1..]); let adv_bytes = adv_builder.into_advertisement(); // ignoring the signature since that's tested elsewhere assert_eq!( &expected, - // adv header + salt + section header + encryption info + identity header - &adv_bytes.as_slice()[1 + 1 + 19 + 2..adv_bytes.as_slice().len() - 64] + // skip adv header + section header + salt + &adv_bytes.as_slice()[1 + 1 + 16..adv_bytes.as_slice().len() - 64] ) } @@ -560,17 +558,15 @@ let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); let key_seed = [22; 32]; - let metadata_key = MetadataKey([33; 16]); - let key_pair = KeyPair::generate(); + let metadata_key = V1IdentityToken([33; 16]); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); + let broadcast_cred = V1BroadcastCredential::new(key_seed, metadata_key, private_key.clone()); let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>( &mut crypto_rng, - EncryptedIdentityDataElementType::Trusted, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); @@ -588,7 +584,7 @@ section_builder .add_de(|_| DummyDataElement { de_type: 100_u32.into(), - data: vec![0; max_total_de_len - 100 - 1] + data: vec![0; max_total_de_len - 100 - 1], }) .unwrap_err() ); @@ -599,7 +595,7 @@ section_builder .add_de(|_| DummyDataElement { de_type: 100_u32.into(), - data: vec![0; max_total_de_len - 100 - 2] + data: vec![0; max_total_de_len - 100 - 2], }) .unwrap_err() ); @@ -609,154 +605,142 @@ fn serialize_max_number_of_public_sections() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); for _ in 0..NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT { - let mut section_builder = - adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de(|_| DummyDataElement { de_type: 100_u32.into(), data: vec![0; 98] }) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); } assert_eq!( - adv_builder.section_builder(PublicSectionEncoder::default()).unwrap_err(), + adv_builder.section_builder(UnencryptedSectionEncoder).unwrap_err(), MaxSectionCountExceeded ); } fn do_mic_encrypted_identity_fixed_key_material_test<W: WriteDataElement>(extra_des: &[W]) { - let metadata_key = MetadataKey([1; 16]); + let identity_token = V1IdentityToken([1; 16]); let key_seed = [2; 32]; let adv_header_byte = 0b00100000; - let raw_salt = [3; 16]; - let section_salt: V1Salt<CryptoProviderImpl> = raw_salt.into(); - let identity_type = EncryptedIdentityDataElementType::Private; + let section_salt: ExtendedV1Salt = [3; 16].into(); let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - RawV1Salt(raw_salt), - &broadcast_cm, + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cred, )) .unwrap(); - for de in extra_des { section_builder.add_de(|_| de).unwrap(); } - // length 53: 19 for encryption info, 18 for identity, 16 for MIC - let section_length = 53 - + extra_des - .iter() - .map(|de| de.de_header().serialize().len() as u8 + de.de_header().len.as_u8()) - .sum::<u8>(); + // now construct expected bytes + // mic length + length of des + let section_length = mic_section_len(extra_des); - let encryption_info = [ - &[ - 0x91, 0x10, // header - 0x00, // scheme (mic) - ], - section_salt.as_slice(), - ] - .concat(); + let mut hmac = + key_seed_hkdf.v1_mic_extended_salt_keys().mic_hmac_key().build_hmac::<CryptoProviderImpl>(); + let nonce = section_salt.compute_nonce::<CryptoProviderImpl>(); - let identity_de_header = - DeHeader { len: 16_u8.try_into().unwrap(), de_type: identity_type.type_code() }; + let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &key_seed_hkdf.v1_mic_extended_salt_keys().aes_key(), + NonceAndCounter::from_nonce(nonce), + ); - let mut hmac = np_hkdf::UnsignedSectionKeys::hmac_key(&key_seed_hkdf).build_hmac(); + // encrypt identity token and de contents + let mut plaintext_identity_token = identity_token.as_slice().to_vec(); + cipher.apply_keystream(&mut plaintext_identity_token); + let ct_identity_token = plaintext_identity_token; + + let mut de_contents = Vec::new(); + for de in extra_des { + de_contents.extend_from_slice(de.de_header().serialize().as_slice()); + let _ = de.write_de_contents(&mut de_contents); + } + cipher.apply_keystream(&mut de_contents); + // just to be sure, we'll construct our test hmac all in one update() call let mut hmac_input = vec![]; hmac_input.extend_from_slice(NP_SVC_UUID.as_slice()); hmac_input.push(adv_header_byte); - // section header - hmac_input.push(section_length); - hmac_input.extend_from_slice(&encryption_info); - let nonce = section_salt.derive::<{ AES_CTR_NONCE_LEN }>(Some(1.into())).unwrap(); + hmac_input.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + hmac_input.extend_from_slice(section_salt.as_slice()); hmac_input.extend_from_slice(nonce.as_slice()); - - hmac_input.extend_from_slice(identity_de_header.serialize().as_slice()); - - let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf), - NonceAndCounter::from_nonce(nonce), - ); - let mut plaintext = metadata_key.0.as_slice().to_vec(); - - for de in extra_des { - plaintext.extend_from_slice(de.de_header().serialize().as_slice()); - let _ = de.write_de_contents(&mut plaintext); - } - - cipher.apply_keystream(&mut plaintext); - let ciphertext = plaintext; - - hmac_input.extend_from_slice(&ciphertext); - + hmac_input.extend_from_slice(&ct_identity_token); + hmac_input.push(section_length); + hmac_input.extend_from_slice(&de_contents); hmac.update(&hmac_input); let mic = hmac.finalize(); let mut expected = vec![]; + expected.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN); + expected.extend_from_slice(section_salt.as_slice()); + expected.extend_from_slice(&ct_identity_token); expected.push(section_length); - expected.extend_from_slice(&encryption_info); - expected.extend_from_slice(identity_de_header.serialize().as_slice()); - expected.extend_from_slice(&ciphertext); + expected.extend_from_slice(&de_contents); expected.extend_from_slice(&mic[..16]); - assert_eq!(&expected, section_builder.into_section().as_slice()); + assert_eq!(&expected, section_builder.into_section::<CryptoProviderImpl>().as_slice()); } -fn do_signature_encrypted_identity_fixed_key_material_test<W: WriteDataElement>(extra_des: &[W]) { - let metadata_key = MetadataKey([1; 16]); - let key_seed = [2; 32]; - let adv_header_byte = 0b00100000; - let raw_salt = [3; 16]; - let section_salt: V1Salt<CryptoProviderImpl> = raw_salt.into(); - let identity_type = EncryptedIdentityDataElementType::Private; - let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let key_pair = KeyPair::generate(); - - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); - - let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - - let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - RawV1Salt(raw_salt), - &broadcast_cm, - )) - .unwrap(); - - for de in extra_des { - section_builder.add_de(|_| de).unwrap(); - } - - // 19 for encryption info, 18 for identity, 64 for sig - let section_length = 19 - + 18 - + 64 +/// Returns the length of a mic section containing `extra_des` +fn mic_section_len<W: WriteDataElement>(extra_des: &[W]) -> u8 { + u8::try_from(SectionMic::CONTENTS_LEN).unwrap() + extra_des .iter() .map(|de| de.de_header().serialize().len() as u8 + de.de_header().len.as_u8()) - .sum::<u8>(); + .sum::<u8>() +} - let encryption_info = [ - &[ - 0x91, 0x10, // header - 0x08, // scheme (signature) - ], - section_salt.as_slice(), - ] - .concat(); - let encryption_info: [u8; EncryptionInfo::TOTAL_DE_LEN] = encryption_info.try_into().unwrap(); +/// Returns the length of a signed section containing `extra_des` +fn sig_section_len<W: WriteDataElement>(extra_des: &[W]) -> u8 { + u8::try_from(crypto_provider::ed25519::SIGNATURE_LENGTH).unwrap() + + extra_des + .iter() + .map(|de| de.de_header().serialize().len() as u8 + de.de_header().len.as_u8()) + .sum::<u8>() +} - let identity_de_header = - DeHeader { len: 16_u8.try_into().unwrap(), de_type: identity_type.type_code() }; - let identity_de_header: [u8; 2] = identity_de_header.serialize().as_slice().try_into().unwrap(); +#[test] +fn signature_encrypted_identity_section_empty() { + do_signature_encrypted_identity_fixed_key_material_test::<DummyDataElement>(&[]); +} + +fn do_signature_encrypted_identity_fixed_key_material_test<W: WriteDataElement>(extra_des: &[W]) { + // input fixed credential data used to encode the adv + let identity_token = V1IdentityToken::from([1; 16]); + let key_seed = [2; 32]; + let section_salt: ExtendedV1Salt = [3; 16].into(); + let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); + let broadcast_cred = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); + + // Build an adv given the provided DEs in extra_des + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let mut section_builder = adv_builder + .section_builder(SignedEncryptedSectionEncoder::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cred, + )) + .unwrap(); + for de in extra_des { + section_builder.add_de(|_| de).unwrap(); + } + let section = section_builder.into_section::<CryptoProviderImpl>(); + + // now manually construct the expected output + let format = [V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN]; + let salt_bytes = section_salt.as_slice(); + let identity_token_bytes = identity_token.as_slice(); + // len of de contents + signature + let section_length = sig_section_len(extra_des); let mut section_body = Vec::new(); for de in extra_des { @@ -764,49 +748,55 @@ let _ = de.write_de_contents(&mut section_body); } - let nonce = section_salt.derive(Some(1.into())).unwrap(); + let nonce = section_salt.compute_nonce::<CryptoProviderImpl>(); - let sig_payload = SectionSignaturePayload::from_deserialized_parts( - adv_header_byte, - section_length, - &encryption_info, + let sig_payload = SectionSignaturePayload::new( + format.as_slice(), + salt_bytes, &nonce, - identity_de_header, - metadata_key, + identity_token.as_slice(), + section_length, §ion_body, ); + let sig = sig_payload.sign::<Ed25519ProviderImpl>(&private_key).to_bytes(); - let mut plaintext = metadata_key.0.as_slice().to_vec(); - plaintext.extend_from_slice(section_body.as_slice()); - plaintext.extend_from_slice(&sig_payload.sign(&key_pair).to_bytes()); - - <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( - &key_seed_hkdf.extended_signed_section_aes_key(), + let mut cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new( + &key_seed_hkdf.v1_signature_keys().aes_key(), NonceAndCounter::from_nonce(nonce), - ) - .apply_keystream(&mut plaintext); - let ciphertext = plaintext; + ); - let mut expected = vec![section_length]; + let mut expected = vec![]; + expected.extend_from_slice(&format); + expected.extend_from_slice(salt_bytes); - expected.extend_from_slice(&encryption_info); - expected.extend_from_slice(&identity_de_header); - expected.extend_from_slice(&ciphertext); + let mut ct_identity_token = Vec::new(); + ct_identity_token.extend_from_slice(identity_token_bytes); + cipher.apply_keystream(&mut ct_identity_token); - assert_eq!(&expected, section_builder.into_section().as_slice()); + expected.extend_from_slice(&ct_identity_token); + expected.push(section_length); + + let mut remaining_ct = Vec::new(); + remaining_ct.extend_from_slice(§ion_body); + remaining_ct.extend_from_slice(&sig); + cipher.apply_keystream(&mut remaining_ct); + + expected.extend_from_slice(&remaining_ct); + + assert_eq!(&expected, section.as_slice()); } -/// Write `section_contents_len` bytes of DE and header into `section_builder` +/// Write `section_contents_len` bytes of DE into `section_builder` pub(crate) fn fill_section_builder<I: SectionEncoder>( section_contents_len: usize, section_builder: &mut SectionBuilder<&mut AdvBuilder, I>, -) { +) -> Result<(), AddDataElementError<GenericDataElementError>> { + let original_len = section_builder.section.len(); // DEs can only go up to 127, so we'll need multiple for long sections for _ in 0..(section_contents_len / 100) { let de_contents = vec![0x33; 98]; section_builder - .add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &de_contents)) - .unwrap(); + .add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &de_contents))?; } let remainder_len = section_contents_len % 100; @@ -816,25 +806,24 @@ } 1 => { // 1 byte header - section_builder - .add_de_res(|_| GenericDataElement::try_from(3_u32.into(), &[])) - .unwrap(); + section_builder.add_de_res(|_| GenericDataElement::try_from(3_u32.into(), &[]))?; } 2 => { // 2 byte header - section_builder - .add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &[])) - .unwrap(); + section_builder.add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &[]))?; } _ => { // 2 byte header + contents as needed - // leave room for section and DE headers + // leave room for section length, section header, and DE headers let de_contents = vec![0x44; remainder_len - 2]; section_builder - .add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &de_contents)) - .unwrap(); + .add_de_res(|_| GenericDataElement::try_from(100_u32.into(), &de_contents))?; } } + + assert_eq!(section_contents_len, section_builder.section.len() - original_len); + + Ok(()) } #[derive(Clone)] @@ -854,17 +843,12 @@ } pub(crate) trait SectionBuilderExt { - fn into_section(self) -> EncodedSection; + fn into_section<C: CryptoProvider>(self) -> EncodedSection; } impl<R: AsMut<AdvBuilder>, I: SectionEncoder> SectionBuilderExt for SectionBuilder<R, I> { /// Convenience method for tests - fn into_section(mut self) -> EncodedSection { - let adv_builder_header_byte = self.adv_builder.as_mut().header_byte(); - Self::build_section( - adv_builder_header_byte, - self.section.into_inner(), - self.section_encoder, - ) + fn into_section<C: CryptoProvider>(self) -> EncodedSection { + Self::build_section::<C>(self.header_len, self.section.into_inner(), self.section_encoder) } }
diff --git a/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs b/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs index 0f5b22a..829123c 100644 --- a/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs +++ b/nearby/presence/np_adv/src/extended/serialize/test_vectors.rs
@@ -16,31 +16,31 @@ extern crate std; -use crate::extended::deserialize::RawV1Salt; +use crate::credential::v1::V1BroadcastCredential; +use crate::extended::de_type::DeType; +use crate::extended::salt::V1Salt; use crate::extended::serialize::AdvertisementType; -use crate::{ - credential::{v1::V1, SimpleBroadcastCryptoMaterial}, - de_type::EncryptedIdentityDataElementType, - extended::serialize::{ - section_tests::{DummyDataElement, SectionBuilderExt}, - AdvBuilder, MicEncryptedSectionEncoder, - }, - MetadataKey, +use crate::extended::serialize::{ + section_tests::{DummyDataElement, SectionBuilderExt}, + AdvBuilder, MicEncryptedSectionEncoder, }; +use crate::extended::V1IdentityToken; +use alloc::format; use anyhow::anyhow; -use crypto_provider::{aes::ctr::AES_CTR_NONCE_LEN, aes::AesKey}; +use crypto_provider::{aes::ctr::AES_CTR_NONCE_LEN, aes::AesKey, ed25519, CryptoProvider}; use crypto_provider_default::CryptoProviderImpl; -use np_hkdf::v1_salt; -use rand_ext::rand::{prelude::SliceRandom as _, Rng as _, SeedableRng as _}; +use np_hkdf::{v1_salt, DerivedSectionKeys}; use serde_json::json; use std::{fs, io::Read as _, prelude::rust_2021::*, println}; -use strum::IntoEnumIterator as _; use test_helper::extract_key_array; +use test_vector_hkdf::TestVectorHkdf; + +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; #[test] fn mic_encrypted_test_vectors() -> Result<(), anyhow::Error> { let full_path = test_helper::get_data_file( - "presence/np_adv/resources/test/mic-encrypted-test-vectors.json", + "presence/np_adv/resources/test/mic-extended-salt-encrypted-test-vectors.json", ); let mut file = fs::File::open(full_path)?; let mut data = String::new(); @@ -54,12 +54,11 @@ for tc in test_cases { { let key_seed = extract_key_array::<32>(&tc, "key_seed"); - let metadata_key = MetadataKey(extract_key_array::<16>(&tc, "metadata_key")); + let identity_token = + V1IdentityToken::from(extract_key_array::<16>(&tc, "identity_token")); let adv_header_byte = extract_key_array::<1>(&tc, "adv_header_byte")[0]; - let section_salt = v1_salt::V1Salt::<CryptoProviderImpl>::from( - extract_key_array::<16>(&tc, "section_salt"), - ); - let identity_type = tc["identity_type"].as_str().map(identity_type_from_label).unwrap(); + let section_salt = + v1_salt::ExtendedV1Salt::from(extract_key_array::<16>(&tc, "section_salt")); let data_elements = tc["data_elements"] .as_array() .unwrap() @@ -74,28 +73,31 @@ assert_eq!( extract_key_array::<16>(&tc, "aes_key").as_slice(), - np_hkdf::UnsignedSectionKeys::aes_key(&hkdf).as_slice() + hkdf.v1_mic_extended_salt_keys().aes_key().as_slice() ); assert_eq!( extract_key_array::<32>(&tc, "section_mic_hmac_key").as_slice(), - np_hkdf::UnsignedSectionKeys::hmac_key(&hkdf).as_bytes() + hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes() ); assert_eq!( extract_key_array::<{ AES_CTR_NONCE_LEN }>(&tc, "nonce").as_slice(), - section_salt.derive::<{ AES_CTR_NONCE_LEN }>(Some(1.into())).unwrap() + section_salt.compute_nonce::<CryptoProviderImpl>() ); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); // make an adv builder in the configuration we need let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - assert_eq!(adv_header_byte, adv_builder.header_byte()); + assert_eq!(adv_header_byte, adv_builder.adv_header().contents()); let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - section_salt.into(), - &broadcast_cm, + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cred, )) .unwrap(); @@ -105,7 +107,7 @@ assert_eq!( hex::decode(tc["encoded_section"].as_str().unwrap()).unwrap(), - section_builder.into_section().as_slice() + section_builder.into_section::<CryptoProviderImpl>().as_slice() ); } } @@ -116,42 +118,57 @@ #[ignore] #[test] fn gen_mic_encrypted_test_vectors() { - let mut rng = rand::rngs::StdRng::from_entropy(); - let mut array = Vec::<serde_json::Value>::new(); - for _ in 0..100 { - let num_des = rng.gen_range(0..=5); + for i in 0_u32..100 { + let test_vector_seed_hkdf = TestVectorHkdf::<CryptoProviderImpl>::new( + "NP V1 MIC test vectors HpakGBH8I+zbcEdxEanIT1r3bkgmL+mWI/kMrPiCzPw", + &i.to_be_bytes(), + ); - let extra_des = (0..num_des) - .map(|_| { - let de_len = rng.gen_range(0..=30); - DummyDataElement { - de_type: rng.gen_range(0_u32..=1_000).into(), - data: rand_ext::random_vec_rc(&mut rng, de_len), - } - }) - .collect::<Vec<_>>(); + let num_des = test_vector_seed_hkdf.derive_range_element("num des", 0_u64..=5); - let metadata_key = MetadataKey(rng.gen()); - let key_seed = rng.gen(); + let extra_des = + (0..num_des) + .map(|de_index| { + let de_len = test_vector_seed_hkdf + .derive_range_element(&format!("de len {}", de_index), 0..=30); + let data = test_vector_seed_hkdf + .derive_vec(&format!("de data {}", de_index), de_len.try_into().unwrap()); + DummyDataElement { + de_type: DeType::from( + u32::try_from(test_vector_seed_hkdf.derive_range_element( + &format!("de type {}", de_index), + 0_u64..=1_000, + )) + .unwrap(), + ), + data, + } + }) + .collect::<Vec<_>>(); + + let identity_token = + V1IdentityToken::from(test_vector_seed_hkdf.derive_array("identity token")); + let key_seed = test_vector_seed_hkdf.derive_array("key seed"); let adv_header_byte = 0b00100000; - let identity_type = - *EncryptedIdentityDataElementType::iter().collect::<Vec<_>>().choose(&mut rng).unwrap(); let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); + let broadcast_cred = V1BroadcastCredential::new( + key_seed, + identity_token, + ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(), + ); let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); - let salt = rng.gen::<[u8; 16]>(); - let section_salt = v1_salt::V1Salt::<CryptoProviderImpl>::from(salt); + let section_salt = + v1_salt::ExtendedV1Salt::from(test_vector_seed_hkdf.derive_array::<16>("salt")); let mut section_builder = adv_builder - .section_builder(MicEncryptedSectionEncoder::<CryptoProviderImpl>::new( - identity_type, - RawV1Salt(salt), - &broadcast_cm, + .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>( + section_salt, + &broadcast_cred, )) .unwrap(); @@ -159,42 +176,24 @@ section_builder.add_de(|_| de).unwrap(); } - let nonce = section_salt.derive::<{ AES_CTR_NONCE_LEN }>(Some(1.into())).unwrap(); - - array - .push(json!({ - "key_seed": hex::encode_upper(key_seed), - "metadata_key": hex::encode_upper(metadata_key.0), - "adv_header_byte": hex::encode_upper([adv_header_byte]), - "section_salt": hex::encode_upper(section_salt.as_slice()), - "identity_type": identity_type_label(identity_type), - "data_elements": extra_des.iter().map(|de| json!({ - "de_type": de.de_type.as_u32(), - "contents": hex::encode_upper(&de.data) - })).collect::<Vec<_>>(), - "aes_key": hex::encode_upper(np_hkdf::UnsignedSectionKeys::aes_key(&key_seed_hkdf).as_slice()), - "nonce": hex::encode_upper(nonce), - "section_mic_hmac_key": hex::encode_upper(np_hkdf::UnsignedSectionKeys::hmac_key(&key_seed_hkdf).as_bytes()), - "encoded_section": hex::encode_upper(section_builder.into_section().as_slice()) - })); + let nonce = section_salt.compute_nonce::<CryptoProviderImpl>(); + let keys = key_seed_hkdf.v1_mic_extended_salt_keys(); + array.push(json!({ + "key_seed": hex::encode_upper(key_seed), + "identity_token": hex::encode_upper(identity_token.as_slice()), + "adv_header_byte": hex::encode_upper([adv_header_byte]), + "section_salt": hex::encode_upper(section_salt.as_slice()), + "data_elements": extra_des.iter().map(|de| json!({ + "de_type": de.de_type.as_u32(), + "contents": hex::encode_upper(&de.data) + })).collect::<Vec<_>>(), + "aes_key": hex::encode_upper(keys.aes_key().as_slice()), + "nonce": hex::encode_upper(nonce), + "section_mic_hmac_key": hex::encode_upper(keys.mic_hmac_key().as_bytes()), + "encoded_section": hex::encode_upper(section_builder.into_section::<CryptoProviderImpl>().as_slice()) + })); } println!("{}", serde_json::ser::to_string_pretty(&array).unwrap()); -} - -fn identity_type_label(t: EncryptedIdentityDataElementType) -> &'static str { - match t { - EncryptedIdentityDataElementType::Private => "private", - EncryptedIdentityDataElementType::Trusted => "trusted", - EncryptedIdentityDataElementType::Provisioned => "provisioned", - } -} - -fn identity_type_from_label(label: &str) -> EncryptedIdentityDataElementType { - match label { - "private" => EncryptedIdentityDataElementType::Private, - "trusted" => EncryptedIdentityDataElementType::Trusted, - "provisioned" => EncryptedIdentityDataElementType::Provisioned, - _ => panic!("unknown label: {}", label), - } + panic!("Don't leave this test enabled. Meanwhile, enjoy the text output above."); }
diff --git a/nearby/presence/np_adv/src/filter/mod.rs b/nearby/presence/np_adv/src/filter/mod.rs index a2b2d9c..e2b37e7 100644 --- a/nearby/presence/np_adv/src/filter/mod.rs +++ b/nearby/presence/np_adv/src/filter/mod.rs
@@ -16,21 +16,18 @@ //! a valid Nearby Presence advertisement and if so which was its corresponding identity //! it matched with. Used as a first pass option to quickly check if a buffer should //! further processed. -use crate::credential::MatchedCredential; +use crate::credential::matched::MatchedCredential; +use crate::header::{NpVersionHeader, V0Encoding, V1AdvHeader}; use crate::legacy::data_elements::DataElementDeserializeError; +use crate::legacy::deserialize::intermediate::{IntermediateAdvContents, LdtAdvContents}; use crate::legacy::deserialize::DecryptedAdvContents; use crate::{ credential::{book::CredentialBook, v0::V0DiscoveryCryptoMaterial}, - legacy, legacy::{ - actions, - actions::ActionsDataElement, - deserialize::{ - DecryptError, EncryptedAdvContents, IntermediateAdvContents, PlainDataElement, - }, + data_elements::actions::{self, ActionsDataElement}, + deserialize::{DecryptError, DeserializedDataElement}, PacketFlavor, }, - parse_adv_header, AdvHeader, V1Header, }; use array_view::ArrayView; use core::fmt::Debug; @@ -91,7 +88,7 @@ } /// The total number of unique boolean action types -const NUM_ACTIONS: usize = 7; +const NUM_ACTIONS: usize = 6; /// Specify which specific actions bits to filter on, will filter on if any of the specified /// actions are matched @@ -117,17 +114,17 @@ B: CredentialBook<'a>, P: CryptoProvider, { - parse_adv_header(adv) + NpVersionHeader::parse(adv) .map(|(remaining, header)| match header { - AdvHeader::V0 => { + NpVersionHeader::V0(encoding) => { let filter = match self { FilterOptions::V0FilterOptions(filter) => filter, FilterOptions::Either(filter, _) => filter, _ => return Err(NoMatch), }; - filter.match_v0_adv::<B, P>(cred_book, remaining) + filter.match_v0_adv::<B, P>(encoding, cred_book, remaining) } - AdvHeader::V1(header) => { + NpVersionHeader::V1(header) => { let filter = match self { FilterOptions::V1FilterOptions(filter) => filter, FilterOptions::Either(_, filter) => filter, @@ -145,6 +142,7 @@ /// match the filter criteria fn match_v0_adv<'a, B, P>( &self, + encoding: V0Encoding, cred_book: &'a B, remaining: &[u8], ) -> Result<FilterResult<B::Matched>, NoMatch> @@ -153,16 +151,16 @@ P: CryptoProvider, { let contents = - legacy::deserialize::deserialize_adv_contents::<P>(remaining).map_err(|_| NoMatch)?; + IntermediateAdvContents::deserialize::<P>(encoding, remaining).map_err(|_| NoMatch)?; match contents { - IntermediateAdvContents::Plaintext(p) => match self.identity { + IntermediateAdvContents::Unencrypted(p) => match self.identity { IdentityFilterType::Public | IdentityFilterType::Any => self .data_elements .match_v0_legible_adv(|| p.data_elements()) .map(|()| FilterResult::Public), _ => Err(NoMatch), }, - IntermediateAdvContents::Ciphertext(c) => match self.identity { + IntermediateAdvContents::Ldt(c) => match self.identity { IdentityFilterType::Private | IdentityFilterType::Any => { let (legible_adv, m) = try_decrypt_and_match::<B, P>(cred_book.v0_iter(), &c)?; self.data_elements @@ -177,7 +175,7 @@ fn try_decrypt_and_match<'cred, B, P>( v0_creds: B::V0Iterator, - adv: &EncryptedAdvContents, + adv: &LdtAdvContents, ) -> Result<(DecryptedAdvContents, B::Matched), NoMatch> where B: CredentialBook<'cred>, @@ -189,9 +187,6 @@ Ok(c) => return Ok((c, m)), Err(e) => match e { DecryptError::DecryptOrVerifyError => continue, - DecryptError::DeserializeError(_) => { - return Err(NoMatch); - } }, } } @@ -203,12 +198,14 @@ fn match_v0_legible_adv<F, I>(&self, data_elements: impl Fn() -> I) -> Result<(), NoMatch> where F: PacketFlavor, - I: Iterator<Item = Result<PlainDataElement<F>, DataElementDeserializeError>>, + I: Iterator<Item = Result<DeserializedDataElement<F>, DataElementDeserializeError>>, { match &self.contains_tx_power { None => Ok(()), Some(c) => { - if c == &data_elements().any(|de| matches!(de, Ok(PlainDataElement::TxPower(_)))) { + if c == &data_elements() + .any(|de| matches!(de, Ok(DeserializedDataElement::TxPower(_)))) + { Ok(()) } else { Err(NoMatch) @@ -224,7 +221,7 @@ } // find if an actions DE exists, if so match on the provided action filter let actions = data_elements().find_map(|de| match de { - Ok(PlainDataElement::Actions(actions)) => Some(actions), + Ok(DeserializedDataElement::Actions(actions)) => Some(actions), _ => None, }); if let Some(actions) = actions { @@ -262,11 +259,7 @@ actions: &ActionsDataElement<F>, ) -> Result<(), NoMatch> { for action in self.actions.as_slice().iter() { - if actions - .action - .has_action(&action.expect("This will always contain Some")) - .unwrap_or(false) - { + if actions.action.has_action(action.expect("This will always contain Some")) { return Ok(()); } } @@ -285,7 +278,7 @@ &self, _cred_book: &'a B, _remaining: &[u8], - _header: V1Header, + _header: V1AdvHeader, ) -> Result<FilterResult<B::Matched>, NoMatch> where B: CredentialBook<'a>,
diff --git a/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs b/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs index ffdeeb9..c395124 100644 --- a/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs +++ b/nearby/presence/np_adv/src/filter/tests/actions_filter_tests.rs
@@ -15,8 +15,10 @@ #![allow(clippy::unwrap_used)] use super::super::*; -use crate::legacy::actions::{ActionBits, InstantTethering, NearbyShare}; +use crate::legacy::data_elements::actions::{ActionBits, InstantTethering, NearbyShare}; use crate::legacy::{Ciphertext, Plaintext}; +use alloc::vec::Vec; +use strum::IntoEnumIterator; #[test] fn new_v0_actions_invalid_length() { @@ -28,7 +30,7 @@ #[test] fn new_v0_actions() { - let actions = [actions::ActionType::ActiveUnlock; 7]; + let actions = [actions::ActionType::ActiveUnlock; 5]; let result = V0ActionsFilter::new_from_slice(&actions); assert!(result.is_ok()); } @@ -55,16 +57,8 @@ // default is all 0 bits let action_bits = ActionBits::<Plaintext>::default(); - let filter = V0ActionsFilter::new_from_slice(&[ - actions::ActionType::ActiveUnlock, - actions::ActionType::NearbyShare, - actions::ActionType::InstantTethering, - actions::ActionType::PhoneHub, - actions::ActionType::Finder, - actions::ActionType::FastPairSass, - actions::ActionType::PresenceManager, - ]) - .expect("7 is a valid length"); + let filter = V0ActionsFilter::new_from_slice(&actions::ActionType::iter().collect::<Vec<_>>()) + .expect("5 is a valid length"); assert_eq!(filter.match_v0_actions(&action_bits.into()), Err(NoMatch)) } @@ -75,16 +69,8 @@ let mut action_bits = ActionBits::<Plaintext>::default(); action_bits.set_action(NearbyShare::from(true)); - let filter = V0ActionsFilter::new_from_slice(&[ - actions::ActionType::ActiveUnlock, - actions::ActionType::NearbyShare, - actions::ActionType::InstantTethering, - actions::ActionType::PhoneHub, - actions::ActionType::Finder, - actions::ActionType::FastPairSass, - actions::ActionType::PresenceManager, - ]) - .expect("7 is a valid length"); + let filter = V0ActionsFilter::new_from_slice(&actions::ActionType::iter().collect::<Vec<_>>()) + .expect("5 is a valid length"); assert_eq!(filter.match_v0_actions(&action_bits.into()), Ok(())) } @@ -96,14 +82,12 @@ action_bits.set_action(NearbyShare::from(true)); let filter = V0ActionsFilter::new_from_slice(&[ + actions::ActionType::CallTransfer, actions::ActionType::ActiveUnlock, actions::ActionType::InstantTethering, actions::ActionType::PhoneHub, - actions::ActionType::Finder, - actions::ActionType::FastPairSass, - actions::ActionType::PresenceManager, ]) - .expect("6 is a valid length"); + .expect("4 is a valid length"); assert_eq!(filter.match_v0_actions(&action_bits.into()), Err(NoMatch)) } @@ -136,3 +120,8 @@ assert_eq!(filter.match_v0_actions(&action_bits.into()), Ok(())) } + +#[test] +fn num_actions_is_correct() { + assert_eq!(actions::ActionType::iter().count(), NUM_ACTIONS); +}
diff --git a/nearby/presence/np_adv/src/filter/tests/data_elements_filter_tests.rs b/nearby/presence/np_adv/src/filter/tests/data_elements_filter_tests.rs index 4a893a2..0b83831 100644 --- a/nearby/presence/np_adv/src/filter/tests/data_elements_filter_tests.rs +++ b/nearby/presence/np_adv/src/filter/tests/data_elements_filter_tests.rs
@@ -13,10 +13,16 @@ // limitations under the License. use super::super::*; -use crate::legacy::actions::{ActionBits, ActiveUnlock}; -use crate::legacy::data_elements::TxPowerDataElement; -use crate::legacy::{Ciphertext, Plaintext}; -use crate::shared_data::TxPower; +use crate::{ + legacy::{ + data_elements::{ + actions::{ActionBits, ActiveUnlock}, + tx_power::TxPowerDataElement, + }, + Ciphertext, Plaintext, + }, + shared_data::TxPower, +}; #[test] fn match_contains_tx_power() { @@ -24,7 +30,7 @@ let tx_power = TxPower::try_from(5).expect("within range"); let result = filter.match_v0_legible_adv(|| { - [Ok(PlainDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power.clone())))] + [Ok(DeserializedDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power)))] .into_iter() }); assert_eq!(result, Ok(())) @@ -44,7 +50,7 @@ let filter = V0DataElementsFilter { contains_tx_power: None, actions_filter: Some(filter) }; let tx_power = TxPower::try_from(5).expect("within range"); let result = filter.match_v0_legible_adv(|| { - [Ok(PlainDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power.clone())))] + [Ok(DeserializedDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power)))] .into_iter() }); assert_eq!(result, Err(NoMatch)) @@ -62,8 +68,8 @@ let result = filter.match_v0_legible_adv(|| { [ - Ok(PlainDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power.clone()))), - Ok(PlainDataElement::Actions(action_bits.into())), + Ok(DeserializedDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power))), + Ok(DeserializedDataElement::Actions(action_bits.into())), ] .into_iter() }); @@ -83,8 +89,8 @@ let result = filter.match_v0_legible_adv(|| { [ - Ok(PlainDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power.clone()))), - Ok(PlainDataElement::Actions(action_bits.into())), + Ok(DeserializedDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power))), + Ok(DeserializedDataElement::Actions(action_bits.into())), ] .into_iter() }); @@ -100,7 +106,7 @@ let tx_power = TxPower::try_from(5).expect("within range"); let result = filter.match_v0_legible_adv(|| { - [Ok(PlainDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power.clone())))] + [Ok(DeserializedDataElement::<Ciphertext>::TxPower(TxPowerDataElement::from(tx_power)))] .into_iter() }); assert_eq!(result, Err(NoMatch))
diff --git a/nearby/presence/np_adv/src/filter/tests/mod.rs b/nearby/presence/np_adv/src/filter/tests/mod.rs index 29d3e7c..42ab177 100644 --- a/nearby/presence/np_adv/src/filter/tests/mod.rs +++ b/nearby/presence/np_adv/src/filter/tests/mod.rs
@@ -13,11 +13,13 @@ // limitations under the License. use crate::credential::book::CredentialBookBuilder; -use crate::credential::KeySeedMatchedCredential; +use crate::credential::matched::KeySeedMatchedCredential; +use crate::extended::V1_ENCODING_UNENCRYPTED; use crate::filter::IdentityFilterType::Any; use crate::filter::{ FilterOptions, FilterResult, NoMatch, V0DataElementsFilter, V0Filter, V1Filter, }; +use crate::header::{VERSION_HEADER_V0_UNENCRYPTED, VERSION_HEADER_V1}; use crypto_provider_default::CryptoProviderImpl; mod actions_filter_tests; @@ -42,9 +44,9 @@ let result = filter.match_advertisement::<_, CryptoProviderImpl>( &empty_cred_book, &[ - 0x0, // adv header - 0x03, // public DE - 0x16, 0x00, // actions + VERSION_HEADER_V0_UNENCRYPTED, + 0x16, + 0x00, // actions ], ); @@ -69,9 +71,9 @@ let result = filter.match_advertisement::<_, CryptoProviderImpl>( &empty_cred_book, &[ - 0x0, // adv header - 0x03, // public DE - 0x16, 0x00, // actions + VERSION_HEADER_V0_UNENCRYPTED, + 0x16, + 0x00, // actions ], ); @@ -96,10 +98,11 @@ let result = filter.match_advertisement::<_, CryptoProviderImpl>( &empty_cred_book, &[ - 0x20, // V1 Advertisement header + VERSION_HEADER_V1, 0x03, // Section Header - 0x03, // Public Identity DE header - 0x15, 0x03, // Length 1 Tx Power DE with value 3 + V1_ENCODING_UNENCRYPTED, + 0x15, + 0x03, // Length 1 Tx Power DE with value 3 ], );
diff --git a/nearby/presence/np_adv/src/filter/tests/v0_filter_tests.rs b/nearby/presence/np_adv/src/filter/tests/v0_filter_tests.rs index 971a39e..9c60e2f 100644 --- a/nearby/presence/np_adv/src/filter/tests/v0_filter_tests.rs +++ b/nearby/presence/np_adv/src/filter/tests/v0_filter_tests.rs
@@ -12,27 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(clippy::unwrap_used)] + use super::super::*; use crate::credential::book::CredentialBookBuilder; +use crate::credential::matched::{KeySeedMatchedCredential, ReferencedMatchedCredential}; use crate::credential::v0::{V0DiscoveryCredential, V0}; -use crate::credential::{ - KeySeedMatchedCredential, MatchableCredential, ReferencedMatchedCredential, -}; +use crate::credential::{v0::V0BroadcastCredential, MatchableCredential}; use crate::filter::IdentityFilterType::{Any, Private, Public}; +use crate::legacy::data_elements::tx_power::TxPowerDataElement; +use crate::legacy::serialize::{AdvBuilder, LdtEncoder}; +use crate::shared_data::TxPower; +use alloc::vec::Vec; use crypto_provider_default::CryptoProviderImpl; -use ldt_np_adv::NP_LEGACY_METADATA_KEY_LEN; +use ldt_np_adv::V0_IDENTITY_TOKEN_LEN; -const METADATA_KEY: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; +const IDENTITY_TOKEN: [u8; V0_IDENTITY_TOKEN_LEN] = [0x33; V0_IDENTITY_TOKEN_LEN]; const KEY_SEED: [u8; 32] = [0x11_u8; 32]; -const PRIVATE_IDENTITY_V0_ADV_CONTENTS: [u8; 19] = [ - 0x21, // private DE - 0x22, 0x22, // salt - // ciphertext - 0x85, 0xBF, 0xA8, 0x83, 0x58, 0x7C, 0x50, 0xCF, 0x98, 0x38, 0xA7, 0x8A, 0xC0, 0x1C, 0x96, 0xF9, -]; -const PUBLIC_IDENTITY_V0_ADV_CONTENTS: [u8; 3] = [ - 0x03, // public DE +const PUBLIC_IDENTITY_V0_ADV_CONTENTS: [u8; 2] = [ 0x16, 0x00, // actions ]; @@ -49,8 +47,11 @@ CryptoProviderImpl, >(&[], &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PUBLIC_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Unencrypted, + &cred_book, + &PUBLIC_IDENTITY_V0_ADV_CONTENTS, + ); assert_eq!(result, Ok(FilterResult::Public)); } @@ -68,8 +69,11 @@ CryptoProviderImpl, >(&[], &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PUBLIC_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + &PUBLIC_IDENTITY_V0_ADV_CONTENTS, + ); assert_eq!(result, Err(NoMatch)); } @@ -87,8 +91,11 @@ CryptoProviderImpl, >(&[], &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PUBLIC_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Unencrypted, + &cred_book, + &PUBLIC_IDENTITY_V0_ADV_CONTENTS, + ); assert_eq!(result, Ok(FilterResult::Public)); } @@ -106,8 +113,11 @@ CryptoProviderImpl, >(&[], &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PRIVATE_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + v0_adv_contents().as_slice(), + ); assert_eq!(result, Err(NoMatch)); } @@ -121,11 +131,12 @@ let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&KEY_SEED); let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&METADATA_KEY); - let discovery_credential = V0DiscoveryCredential::new(KEY_SEED, metadata_key_hmac); + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&IDENTITY_TOKEN); let match_data: KeySeedMatchedCredential = KEY_SEED.into(); - let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = - [MatchableCredential { discovery_credential, match_data: match_data.clone() }]; + let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = [MatchableCredential { + discovery_credential: V0DiscoveryCredential::new(KEY_SEED, metadata_key_hmac), + match_data: match_data.clone(), + }]; let cred_book = CredentialBookBuilder::<KeySeedMatchedCredential>::build_cached_slice_book::< 0, @@ -133,8 +144,11 @@ CryptoProviderImpl, >(&v0_creds, &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PRIVATE_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + v0_adv_contents().as_slice(), + ); assert_eq!(result, Ok(FilterResult::Private(ReferencedMatchedCredential::from(&match_data)))); } @@ -148,11 +162,12 @@ let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&KEY_SEED); let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&METADATA_KEY); - let discovery_credential = V0DiscoveryCredential::new(KEY_SEED, metadata_key_hmac); + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&IDENTITY_TOKEN); let match_data: KeySeedMatchedCredential = KEY_SEED.into(); - let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = - [MatchableCredential { discovery_credential, match_data: match_data.clone() }]; + let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = [MatchableCredential { + discovery_credential: V0DiscoveryCredential::new(KEY_SEED, metadata_key_hmac), + match_data: match_data.clone(), + }]; let cred_book = CredentialBookBuilder::<KeySeedMatchedCredential>::build_cached_slice_book::< 0, @@ -160,8 +175,11 @@ CryptoProviderImpl, >(&v0_creds, &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PRIVATE_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + v0_adv_contents().as_slice(), + ); assert_eq!(result, Ok(FilterResult::Private(ReferencedMatchedCredential::from(&match_data)))); } @@ -180,10 +198,11 @@ let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&METADATA_KEY); - let discovery_credential = V0DiscoveryCredential::new(key_seed, metadata_key_hmac); - let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = - [MatchableCredential { discovery_credential, match_data: KEY_SEED.into() }]; + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&IDENTITY_TOKEN); + let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = [MatchableCredential { + discovery_credential: V0DiscoveryCredential::new(key_seed, metadata_key_hmac), + match_data: KEY_SEED.into(), + }]; let cred_book = CredentialBookBuilder::<KeySeedMatchedCredential>::build_cached_slice_book::< 0, @@ -191,8 +210,11 @@ CryptoProviderImpl, >(&v0_creds, &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PRIVATE_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + v0_adv_contents().as_slice(), + ); assert_eq!(result, Err(NoMatch)); } @@ -204,9 +226,10 @@ data_elements: V0DataElementsFilter { contains_tx_power: None, actions_filter: None }, }; - let discovery_credential = V0DiscoveryCredential::new(KEY_SEED, [0u8; 32]); - let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = - [MatchableCredential { discovery_credential, match_data: KEY_SEED.into() }]; + let v0_creds: [MatchableCredential<V0, KeySeedMatchedCredential>; 1] = [MatchableCredential { + discovery_credential: V0DiscoveryCredential::new(KEY_SEED, [0u8; 32]), + match_data: KEY_SEED.into(), + }]; let cred_book = CredentialBookBuilder::<KeySeedMatchedCredential>::build_cached_slice_book::< 0, @@ -214,8 +237,21 @@ CryptoProviderImpl, >(&v0_creds, &[]); - let result = - filter.match_v0_adv::<_, CryptoProviderImpl>(&cred_book, &PRIVATE_IDENTITY_V0_ADV_CONTENTS); + let result = filter.match_v0_adv::<_, CryptoProviderImpl>( + V0Encoding::Ldt, + &cred_book, + v0_adv_contents().as_slice(), + ); assert_eq!(result, Err(NoMatch)); } + +/// Returns the contents of an advertisement after the version header. +fn v0_adv_contents() -> Vec<u8> { + let broadcast_cm = V0BroadcastCredential::new(KEY_SEED, IDENTITY_TOKEN.into()); + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new([0x22; 2].into(), &broadcast_cm)); + + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); + builder.into_advertisement().unwrap().as_slice()[1..].to_vec() +}
diff --git a/nearby/presence/np_adv/src/header.rs b/nearby/presence/np_adv/src/header.rs new file mode 100644 index 0000000..dc0b96f --- /dev/null +++ b/nearby/presence/np_adv/src/header.rs
@@ -0,0 +1,165 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! NP version header (the first byte) support. +//! +//! The version header byte is 3 bits of version followed by 5 reserved bits. +//! +//! For V0 (`0b000`), the first 3 of the reserved bits identify the encoding +//! scheme used, and the last 2 are still reserved. + +use nom::{combinator, number}; + +// 3-bit versions (high 3 bits in version header) +const PROTOCOL_VERSION_LEGACY: u8 = 0; +const PROTOCOL_VERSION_EXTENDED: u8 = 1; + +// 3-bit encoding ids (3 bits after version, leaving 2 reserved bits) +const V0_ENCODING_SCHEME_ID_UNENCRYPTED: u8 = 0; +const V0_ENCODING_SCHEME_ID_LDT: u8 = 1; + +/// Version header byte for V1 +pub const VERSION_HEADER_V1: u8 = PROTOCOL_VERSION_EXTENDED << 5; + +/// Version header byte for V0 with the unencrypted encoding +pub const VERSION_HEADER_V0_UNENCRYPTED: u8 = + (PROTOCOL_VERSION_LEGACY << 5) | (V0_ENCODING_SCHEME_ID_UNENCRYPTED << 2); + +/// Version header byte for V0 with the LDT encoding +pub const VERSION_HEADER_V0_LDT: u8 = + (PROTOCOL_VERSION_LEGACY << 5) | (V0_ENCODING_SCHEME_ID_LDT << 2); + +/// The first byte in the NP svc data. It defines which version of the protocol +/// is used for the rest of the svc data. +#[derive(Debug, PartialEq, Eq, Clone)] +pub(crate) enum NpVersionHeader { + V0(V0Encoding), + V1(V1AdvHeader), +} + +impl NpVersionHeader { + /// Parse a NP advertisement header. + /// + /// This can be used on all versions of advertisements since it's the header that determines the + /// version. + /// + /// Returns a `nom::IResult` with the parsed header and the remaining bytes of the advertisement. + pub(crate) fn parse(adv: &[u8]) -> nom::IResult<&[u8], Self> { + combinator::map_opt(number::complete::u8, |version_header| match version_header { + VERSION_HEADER_V0_UNENCRYPTED => Some(NpVersionHeader::V0(V0Encoding::Unencrypted)), + VERSION_HEADER_V0_LDT => Some(NpVersionHeader::V0(V0Encoding::Ldt)), + VERSION_HEADER_V1 => Some(NpVersionHeader::V1(V1AdvHeader::new(version_header))), + _ => None, + })(adv) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub(crate) enum V0Encoding { + Unencrypted, + Ldt, +} + +/// A parsed NP Version Header that indicates the V1 protocol is in use. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct V1AdvHeader { + header_byte: u8, +} + +impl V1AdvHeader { + pub(crate) fn new(header_byte: u8) -> Self { + Self { header_byte } + } + + /// The version header byte + pub(crate) fn contents(&self) -> u8 { + self.header_byte + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + extern crate std; + + use nom::error; + + #[test] + fn parse_header_v0_unencrypted() { + let (_, header) = NpVersionHeader::parse(&[0x00]).unwrap(); + assert_eq!(NpVersionHeader::V0(V0Encoding::Unencrypted), header); + } + + #[test] + fn parse_header_v0_ldt() { + let (_, header) = NpVersionHeader::parse(&[0x04]).unwrap(); + assert_eq!(NpVersionHeader::V0(V0Encoding::Ldt), header); + } + + #[test] + fn parse_header_v0_nonzero_invalid_encoding() { + let input = &[0x08]; + assert_eq!( + nom::Err::Error(error::Error { + input: input.as_slice(), + code: error::ErrorKind::MapOpt, + }), + NpVersionHeader::parse(input).unwrap_err() + ); + } + + #[test] + fn parse_header_v0_nonzero_reserved() { + let input = &[0x01]; + assert_eq!( + nom::Err::Error(error::Error { + input: input.as_slice(), + code: error::ErrorKind::MapOpt, + }), + NpVersionHeader::parse(input).unwrap_err() + ); + } + + #[test] + fn parse_header_v1_nonzero_reserved() { + let input = &[0x30]; + assert_eq!( + nom::Err::Error(error::Error { + input: input.as_slice(), + code: error::ErrorKind::MapOpt, + }), + NpVersionHeader::parse(input).unwrap_err() + ); + } + + #[test] + fn parse_header_bad_version() { + let input = &[0x80]; + assert_eq!( + nom::Err::Error(error::Error { + input: input.as_slice(), + code: error::ErrorKind::MapOpt, + }), + NpVersionHeader::parse(input).unwrap_err() + ); + } + + #[test] + fn parse_header_v1() { + let (_, header) = NpVersionHeader::parse(&[0x20]).unwrap(); + assert_eq!(NpVersionHeader::V1(V1AdvHeader::new(0x20)), header); + } +}
diff --git a/nearby/presence/np_adv/src/header_parse_tests.rs b/nearby/presence/np_adv/src/header_parse_tests.rs deleted file mode 100644 index f6b5533..0000000 --- a/nearby/presence/np_adv/src/header_parse_tests.rs +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -use super::*; - -extern crate std; - -use nom::error; - -#[test] -fn parse_header_v0() { - let (_, header) = parse_adv_header(&[0x00]).unwrap(); - assert_eq!(AdvHeader::V0, header); -} - -#[test] -fn parse_header_v0_nonzero_reserved() { - let input = &[0x01]; - assert_eq!( - nom::Err::Error(error::Error { input: input.as_slice(), code: error::ErrorKind::Verify }), - parse_adv_header(input).unwrap_err() - ); -} - -#[test] -fn parse_header_v1_nonzero_reserved() { - let input = &[0x30]; - assert_eq!( - nom::Err::Error(error::Error { input: input.as_slice(), code: error::ErrorKind::Verify }), - parse_adv_header(input).unwrap_err() - ); -} - -#[test] -fn parse_header_bad_version() { - let input = &[0x80]; - assert_eq!( - nom::Err::Error(error::Error { input: input.as_slice(), code: error::ErrorKind::Verify }), - parse_adv_header(input).unwrap_err() - ); -} - -#[test] -fn parse_header_v1() { - let (_, header) = parse_adv_header(&[0x20]).unwrap(); - assert_eq!(AdvHeader::V1(V1Header { header_byte: 0x20 }), header); -}
diff --git a/nearby/presence/np_adv/src/helpers.rs b/nearby/presence/np_adv/src/helpers.rs new file mode 100644 index 0000000..f76fb9a --- /dev/null +++ b/nearby/presence/np_adv/src/helpers.rs
@@ -0,0 +1,39 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use nom::{bytes, combinator}; + +/// Nom parser for a `[u8; N]`. +pub(crate) fn parse_byte_array<const N: usize>(input: &[u8]) -> nom::IResult<&[u8], [u8; N]> { + combinator::map_res(bytes::complete::take(N), |slice: &[u8]| slice.try_into())(input) +} + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_empty_array() { + assert_eq!(([1_u8, 2, 3].as_slice(), []), parse_byte_array::<0>(&[1, 2, 3]).unwrap()) + } + + #[test] + fn parse_nonempty_array() { + assert_eq!( + ([4_u8, 5, 6].as_slice(), [1, 2, 3]), + parse_byte_array::<3>(&[1, 2, 3, 4, 5, 6]).unwrap() + ) + } +}
diff --git a/nearby/presence/np_adv/src/legacy/actions/mod.rs b/nearby/presence/np_adv/src/legacy/actions/mod.rs deleted file mode 100644 index e0f4514..0000000 --- a/nearby/presence/np_adv/src/legacy/actions/mod.rs +++ /dev/null
@@ -1,443 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The "Actions" data element and associated types. -//! -//! This DE is somewhat more complex than other DEs. Whether or not it supports a particular flavor -//! depends on the actions set, so it has to be treated as two separate types based on which -//! flavor type parameter is used. -use crate::{ - legacy::{ - data_elements::{DataElement, DataElementDeserializeError}, - de_type::{DataElementType, PlainDataElementType}, - serialize::{DataElementBundle, ToDataElementBundle}, - Ciphertext, PacketFlavor, PacketFlavorEnum, Plaintext, - }, - shared_data::ContextSyncSeqNum, -}; -#[cfg(feature = "devtools")] -use core::ops::Range; -use core::{marker, num, ops}; -use nom::{bytes, combinator, error}; -use strum::IntoEnumIterator as _; - -mod macros; -#[cfg(test)] -pub(crate) mod tests; - -/// Actions DE. -/// Only as many DE payload bytes will be present as needed to represent all set bits that are encoded, -/// with a lower bound of 1 byte in the special case of no set action bits, and an upper bound -/// of 3 bytes occupied by the DE payload. -#[derive(Debug, PartialEq, Eq)] -pub struct ActionsDataElement<F: PacketFlavor> { - /// The action bits - pub action: ActionBits<F>, -} - -pub(crate) const ACTIONS_MAX_LEN: usize = 3; - -impl<F> ActionsDataElement<F> -where - F: PacketFlavor, - ActionsDataElement<F>: DataElement, -{ - pub(crate) const ACTIONS_LEN: ops::RangeInclusive<usize> = (1..=ACTIONS_MAX_LEN); - - /// Generic deserialize, not meant to be called directly -- use [DataElement] impls instead. - fn deserialize(de_contents: &[u8]) -> Result<Self, DataElementDeserializeError> { - combinator::all_consuming::<&[u8], _, error::Error<&[u8]>, _>(combinator::map( - bytes::complete::take_while_m_n(0, ACTIONS_MAX_LEN, |_| true), - |bytes: &[u8]| { - let mut action_bytes = [0_u8; 4]; - action_bytes[..bytes.len()].copy_from_slice(bytes); - u32::from_be_bytes(action_bytes) - }, - ))(de_contents) - .map_err(|_| DataElementDeserializeError::DeserializeError { - de_type: Self::DE_TYPE_VARIANT, - }) - .map(|(_remaining, actions)| actions) - .and_then(|action_bits_num| { - let action = ActionBits::try_from(action_bits_num).map_err(|e| { - DataElementDeserializeError::FlavorNotSupported { - de_type: Self::DE_TYPE_VARIANT, - flavor: e.flavor, - } - })?; - Ok(Self { action }) - }) - } -} - -impl<F: PacketFlavor> From<ActionBits<F>> for ActionsDataElement<F> { - fn from(action: ActionBits<F>) -> Self { - Self { action } - } -} - -impl<F: PacketFlavor> ToDataElementBundle<F> for ActionsDataElement<F> { - fn to_de_bundle(&self) -> DataElementBundle<F> { - let action_byte_len = self.action.bytes_used(); - let slice = &self.action.bits.to_be_bytes()[..action_byte_len]; - - DataElementBundle::try_from(PlainDataElementType::Actions, slice) - .expect("Length < max DE size") - } -} - -impl DataElement for ActionsDataElement<Plaintext> { - const DE_TYPE_VARIANT: DataElementType = DataElementType::Actions; - - fn supports_flavor(flavor: PacketFlavorEnum) -> bool { - match flavor { - PacketFlavorEnum::Plaintext => true, - PacketFlavorEnum::Ciphertext => false, - } - } - - fn deserialize<F: PacketFlavor>( - de_contents: &[u8], - ) -> Result<Self, DataElementDeserializeError> { - match F::ENUM_VARIANT { - PacketFlavorEnum::Plaintext => ActionsDataElement::deserialize(de_contents), - PacketFlavorEnum::Ciphertext => Err(DataElementDeserializeError::FlavorNotSupported { - de_type: DataElementType::Actions, - flavor: F::ENUM_VARIANT, - }), - } - } -} - -impl DataElement for ActionsDataElement<Ciphertext> { - const DE_TYPE_VARIANT: DataElementType = DataElementType::Actions; - - fn supports_flavor(flavor: PacketFlavorEnum) -> bool { - match flavor { - PacketFlavorEnum::Plaintext => false, - PacketFlavorEnum::Ciphertext => true, - } - } - - fn deserialize<F: PacketFlavor>( - de_contents: &[u8], - ) -> Result<Self, DataElementDeserializeError> { - match F::ENUM_VARIANT { - PacketFlavorEnum::Plaintext => Err(DataElementDeserializeError::FlavorNotSupported { - de_type: DataElementType::Actions, - flavor: F::ENUM_VARIANT, - }), - PacketFlavorEnum::Ciphertext => ActionsDataElement::deserialize(de_contents), - } - } -} - -/// Container for the 24 bits defined for "actions" (feature flags and the like). -/// This internally stores a u32, but only the 24 highest bits of this -/// field will actually ever be populated. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct ActionBits<F: PacketFlavor> { - bits: u32, - // marker for element type - flavor: marker::PhantomData<F>, -} - -impl<F: PacketFlavor> ActionBits<F> { - /// Returns the actions bits as a u32. The upper limit of an actions field is 3 bytes, - /// so the last bytes of this u32 will always be 0 - pub fn as_u32(self) -> u32 { - self.bits - } - - /// Return whether a boolean action type is set in this data element, or `None` if the given - /// action type does not represent a boolean. - pub fn has_action(&self, action_type: &ActionType) -> Option<bool> { - (action_type.bits_len() == 1).then_some(self.bits_for_type(action_type) != 0) - } - - /// Return the context sync sequence number. - pub fn context_sync_seq_num(&self) -> ContextSyncSeqNum { - ContextSyncSeqNum::try_from(self.bits_for_type(&ActionType::ContextSyncSeqNum) as u8) - .expect("Masking with ActionType::ContextSyncSeqNum should always be in range") - } -} - -impl<F: PacketFlavor> Default for ActionBits<F> { - fn default() -> Self { - ActionBits { - bits: 0, // no bits set - flavor: marker::PhantomData, - } - } -} - -/// At least one action doesn't support the required flavor -#[derive(PartialEq, Eq, Debug)] -pub struct FlavorNotSupported { - flavor: PacketFlavorEnum, -} - -lazy_static::lazy_static! { - /// All bits for plaintext action types: 1 where a plaintext action could have a bit, 0 elsewhere. - static ref ALL_PLAINTEXT_ELEMENT_BITS: u32 = ActionType::iter() - .filter(|t| t.supports_flavor(PacketFlavorEnum::Plaintext)) - .map(|t| t.all_bits()) - .fold(0_u32, |accum, bits| accum | bits); -} - -lazy_static::lazy_static! { - /// All bits for ciphertext action types: 1 where a ciphertext action could have a bit, 0 elsewhere. - static ref ALL_CIPHERTEXT_ELEMENT_BITS: u32 = ActionType::iter() - .filter(|t| t.supports_flavor(PacketFlavorEnum::Ciphertext)) - .map(|t| t.all_bits()) - .fold(0_u32, |accum, bits| accum | bits); -} - -impl<F: PacketFlavor> ActionBits<F> { - /// Tries to create ActionBits from a u32, returning error in the event a specific bit is set for - /// an unsupported flavor - pub fn try_from(value: u32) -> Result<Self, FlavorNotSupported> { - let ok_bits: u32 = match F::ENUM_VARIANT { - PacketFlavorEnum::Plaintext => *ALL_PLAINTEXT_ELEMENT_BITS, - PacketFlavorEnum::Ciphertext => *ALL_CIPHERTEXT_ELEMENT_BITS, - }; - - // no bits set beyond what's allowed for this flavor - if value | ok_bits == ok_bits { - Ok(Self { bits: value, flavor: marker::PhantomData }) - } else { - Err(FlavorNotSupported { flavor: F::ENUM_VARIANT }) - } - } - - /// Set the bits for the provided element. - /// Bits outside the range set by the action will be unaffected. - pub fn set_action<E: ToActionElement<F>>(&mut self, to_element: E) { - let element = to_element.to_action_element(); - let len = element.len.get(); - - // validate that the element is not horribly broken - debug_assert!(len + element.index <= 32); - // must not have bits set past the high `len` bits - debug_assert_eq!(0, element.bits >> (8 - len)); - - // 0-extend to u32 - let byte_extended = element.bits as u32; - // Shift so that the high bit is at the desired index. - // Won't overflow since length > 0. - let bits_in_position = byte_extended << (32 - len - element.index); - - // We want to effectively clear out the bits already in place, so we don't want to just |=. - // Instead, we construct a u32 with all 1s above and below the relevant bits and &=, so that - // if the new bits are 0, the stored bits will be cleared. - - // avoid overflow when index = 0 -- need zero 1 bits to the left in that case - let left_1s = u32::MAX.checked_shl(32 - element.index).unwrap_or(0); - // avoid underflow when index + len = 32 -- zero 1 bits to the right - let right_1s = u32::MAX.checked_shr(element.index + len).unwrap_or(0); - let mask = left_1s | right_1s; - let bits_for_other_actions = self.bits & mask; - self.bits = bits_for_other_actions | bits_in_position; - } - - /// How many bytes (1-3) are needed to represent the set bits, starting from the most - /// significant bit. The lower bound of 1 is because the unique special case of - /// an actions field of all zeroes is required by the spec to occupy exactly one byte. - pub(crate) fn bytes_used(&self) -> usize { - let bits_used = 32 - self.bits.trailing_zeros(); - let raw_count = (bits_used as usize + 7) / 8; - if raw_count == 0 { - 1 // Uncommon case - should only be hit for all-zero action bits - } else { - raw_count - } - } - - /// Return the bits for a given action type as the low bits in the returned u32. - /// - /// For example, when extracting the bits `B` from `0bXXXXXXXXXXBBBBBBXXXXXXXXXXXXXXXX`, the - /// return value will be `0b00000000000000000000000000BBBBBB`. - pub fn bits_for_type(&self, action_type: &ActionType) -> u32 { - self.bits << action_type.high_bit_index() >> (32 - action_type.bits_len()) - } -} - -/// The encoded form of an individual action element. -#[derive(Debug, Clone, Copy)] -pub struct ActionElementBits<F: PacketFlavor> { - /// Offset from the high bit in `ActionBits.bits`, which would be bit 0 of byte 0 of the big-endian - /// representation. - /// Must leave enough room for `len` bits in a u32; that is, `index + len <= 32`. - index: u32, - /// Number of bits used. - /// `len + index <= 32` must be true. - len: num::NonZeroU32, - /// Returns the bits to set as the lower `len` bits of the byte. - bits: u8, - /// Marker for whether it can be used in plaintext or encrypted data elements. - flavor: marker::PhantomData<F>, -} - -/// Core trait for an individual action -pub trait ActionElement { - /// The offset from the high bit in the eventual bit sequence of all actions. - /// See [ActionElementBits.index]. - /// - /// Each implementation must have a non-overlapping sequence of bits defined by - /// `HIGH_BIT_INDEX` and `BITS_LEN` w.r.t every other implementation. - const HIGH_BIT_INDEX: u32; - /// The number of high bits in a `u8` that should be used when assembling the complete - /// action bit vector. - /// - /// Must be >0. - const BITS_LEN: u32; - /// Forces implementations to have a matching enum variant so the enum can be kept up to date. - const ACTION_TYPE: ActionType; - - /// Returns whether or not this action supports the provided `flavor`. - /// - /// Must match the implementations of [ToActionElement]. - fn supports_flavor(flavor: PacketFlavorEnum) -> bool; - - /// Returns true if the bits for this element are all zero, or if the flavor is supported. - fn action_is_supported_or_not_set(bits: u32, flavor: PacketFlavorEnum) -> bool { - let shifted = bits << Self::HIGH_BIT_INDEX; - let masked = shifted & (!(u32::MAX >> Self::BITS_LEN)); - - (masked == 0) || Self::supports_flavor(flavor) - } -} - -/// An analog of `Into` tailored to converting structs modeling specific action elements into the -/// representation needed by [ActionBits]. -pub trait ToActionElement<F: PacketFlavor>: ActionElement { - /// Convert the high-level representation of an element into the literal bits needed. - fn to_action_element(&self) -> ActionElementBits<F> { - ActionElementBits { - index: Self::HIGH_BIT_INDEX, - len: Self::BITS_LEN.try_into().expect("all elements must have nonzero len"), - bits: self.bits(), - flavor: marker::PhantomData, - } - } - - /// Returns the bits that should be set starting at `Self::INDEX`. - /// - /// Must not have more than the low `len()` bits set. - fn bits(&self) -> u8; -} - -/// Provides a way to iterate over all action types. -#[derive(Clone, Copy, strum_macros::EnumIter, PartialEq, Eq, Hash, Debug)] -#[allow(missing_docs)] -pub enum ActionType { - ContextSyncSeqNum, - ActiveUnlock, - NearbyShare, - InstantTethering, - PhoneHub, - Finder, - FastPairSass, - PresenceManager, -} - -impl ActionType { - /// A u32 with all possible bits for this action type set - const fn all_bits(&self) -> u32 { - (u32::MAX << (32_u32 - self.bits_len())) >> self.high_bit_index() - } - - /// Get the range of the bits occupied used by this bit index. For example, if the action type - /// uses the 5th and 6th bits, the returned range will be (5..7). - /// (0 is the index of the most significant bit). - #[cfg(feature = "devtools")] - pub const fn bits_range_for_devtools(&self) -> Range<u32> { - let high_bit_index = self.high_bit_index(); - high_bit_index..high_bit_index + self.bits_len() - } - - const fn high_bit_index(&self) -> u32 { - match self { - ActionType::ContextSyncSeqNum => ContextSyncSeqNum::HIGH_BIT_INDEX, - ActionType::ActiveUnlock => ActiveUnlock::HIGH_BIT_INDEX, - ActionType::NearbyShare => NearbyShare::HIGH_BIT_INDEX, - ActionType::InstantTethering => InstantTethering::HIGH_BIT_INDEX, - ActionType::PhoneHub => PhoneHub::HIGH_BIT_INDEX, - ActionType::Finder => Finder::HIGH_BIT_INDEX, - ActionType::FastPairSass => FastPairSass::HIGH_BIT_INDEX, - ActionType::PresenceManager => PresenceManager::HIGH_BIT_INDEX, - } - } - - const fn bits_len(&self) -> u32 { - match self { - ActionType::ContextSyncSeqNum => ContextSyncSeqNum::BITS_LEN, - ActionType::ActiveUnlock => ActiveUnlock::BITS_LEN, - ActionType::NearbyShare => NearbyShare::BITS_LEN, - ActionType::InstantTethering => InstantTethering::BITS_LEN, - ActionType::PhoneHub => PhoneHub::BITS_LEN, - ActionType::Finder => Finder::BITS_LEN, - ActionType::FastPairSass => FastPairSass::BITS_LEN, - ActionType::PresenceManager => PresenceManager::BITS_LEN, - } - } - - pub(crate) fn supports_flavor(&self, flavor: PacketFlavorEnum) -> bool { - match self { - ActionType::ContextSyncSeqNum => ContextSyncSeqNum::supports_flavor(flavor), - ActionType::ActiveUnlock => ActiveUnlock::supports_flavor(flavor), - ActionType::NearbyShare => NearbyShare::supports_flavor(flavor), - ActionType::InstantTethering => InstantTethering::supports_flavor(flavor), - ActionType::PhoneHub => PhoneHub::supports_flavor(flavor), - ActionType::Finder => Finder::supports_flavor(flavor), - ActionType::FastPairSass => FastPairSass::supports_flavor(flavor), - ActionType::PresenceManager => PresenceManager::supports_flavor(flavor), - } - } -} - -impl ActionElement for ContextSyncSeqNum { - const HIGH_BIT_INDEX: u32 = 0; - const BITS_LEN: u32 = 4; - const ACTION_TYPE: ActionType = ActionType::ContextSyncSeqNum; - - fn supports_flavor(flavor: PacketFlavorEnum) -> bool { - match flavor { - PacketFlavorEnum::Plaintext => true, - PacketFlavorEnum::Ciphertext => true, - } - } -} - -impl ToActionElement<Plaintext> for ContextSyncSeqNum { - fn bits(&self) -> u8 { - self.as_u8() - } -} - -impl ToActionElement<Ciphertext> for ContextSyncSeqNum { - fn bits(&self) -> u8 { - self.as_u8() - } -} - -// enabling an element for public adv requires privacy approval due to fingerprinting risk - -macros::boolean_element!(ActiveUnlock, 8, ciphertext_only); -macros::boolean_element!(NearbyShare, 9, plaintext_and_ciphertext); -macros::boolean_element!(InstantTethering, 10, ciphertext_only); -macros::boolean_element!(PhoneHub, 11, ciphertext_only); -macros::boolean_element!(PresenceManager, 12, ciphertext_only); -macros::boolean_element!(Finder, 13, plaintext_and_ciphertext); -macros::boolean_element!(FastPairSass, 14, plaintext_and_ciphertext);
diff --git a/nearby/presence/np_adv/src/legacy/actions/tests.rs b/nearby/presence/np_adv/src/legacy/actions/tests.rs deleted file mode 100644 index 6e68211..0000000 --- a/nearby/presence/np_adv/src/legacy/actions/tests.rs +++ /dev/null
@@ -1,368 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use crate::legacy::{ - actions::*, serialize::ToDataElementBundle, Ciphertext, PacketFlavorEnum, Plaintext, -}; -use std::collections; - -#[test] -fn set_context_sync_works() { - let mut actions = ActionBits::<Plaintext>::default(); - - actions.set_action(ContextSyncSeqNum::try_from(15).unwrap()); - assert_eq_hex(0xF0000000, actions.bits); - - assert_eq!(actions.bits_for_type(&ActionType::ContextSyncSeqNum), 15); -} - -#[test] -fn set_context_sync_doesnt_clobber_neighboring_bit() { - let mut actions = ActionBits::<Plaintext>::default(); - - // set bit just below - actions.bits |= 0x8000000; - - actions.set_action(ContextSyncSeqNum::try_from(15).unwrap()); - assert_eq_hex(0xF8000000, actions.bits); - - assert_eq!(actions.bits_for_type(&ActionType::ContextSyncSeqNum), 15); -} - -#[test] -fn unset_context_sync_works() { - let mut actions = ActionBits::<Plaintext> { - // all 1s - bits: u32::MAX, - ..Default::default() - }; - - actions.set_action(ContextSyncSeqNum::try_from(0).unwrap()); - assert_eq_hex(0x0FFFFFFF, actions.bits); - - assert_eq!(actions.bits_for_type(&ActionType::ContextSyncSeqNum), 0); -} - -#[test] -fn set_ns_works() { - let mut actions = ActionBits::<Plaintext>::default(); - - actions.set_action(NearbyShare::from(true)); - assert_eq_hex(0x00400000, actions.bits); - - assert_eq!(actions.bits_for_type(&ActionType::NearbyShare), 1); - assert_eq!(actions.bits_for_type(&ActionType::ActiveUnlock), 0); - assert_eq!(actions.bits_for_type(&ActionType::InstantTethering), 0); -} - -#[test] -fn set_ns_doesnt_clobber_others() { - let mut actions = ActionBits::<Plaintext>::default(); - - // set neighboring bits - actions.bits |= 0x00120000; - - actions.set_action(NearbyShare::from(true)); - assert_eq_hex(0x00520000, actions.bits); - - assert_eq!(actions.bits_for_type(&ActionType::NearbyShare), 1); - assert_eq!(actions.bits_for_type(&ActionType::PhoneHub), 1); - assert_eq!(actions.bits_for_type(&ActionType::FastPairSass), 1); -} - -#[test] -fn unset_ns_works() { - let mut actions = ActionBits::<Plaintext> { - // all 1s - bits: u32::MAX, - ..Default::default() - }; - - actions.set_action(NearbyShare::from(false)); - assert_eq_hex(0xFFBFFFFF, actions.bits); -} - -#[test] -fn set_last_bit_works() { - let mut actions = ActionBits::<Plaintext>::default(); - - actions.set_action(LastBit::from(true)); - assert_eq_hex(0x0100, actions.bits); -} - -#[test] -fn set_last_bit_doesnt_clobber_others() { - let mut actions = ActionBits::<Plaintext>::default(); - - // set neighboring bits - actions.bits |= 0x200; - - actions.set_action(LastBit::from(true)); - assert_eq_hex(0x300, actions.bits); -} - -#[test] -fn unset_last_bit_works() { - let mut actions = ActionBits::<Plaintext> { - // all 1s - bits: u32::MAX, - ..Default::default() - }; - - actions.set_action(LastBit::from(false)); - assert_eq_hex(0xFFFFFEFF, actions.bits); -} - -#[test] -fn bytes_used_works() { - let mut actions = ActionBits::<Plaintext>::default(); - - // Special-case: All-zeroes should lead to a single byte being used. - assert_eq!(1, actions.bytes_used()); - - actions.set_action(ContextSyncSeqNum::try_from(3).unwrap()); - assert_eq!(1, actions.bytes_used()); - - actions.set_action(NearbyShare::from(true)); - assert_eq!(2, actions.bytes_used()); - - actions.set_action(LastBit::from(true)); - assert_eq!(3, actions.bytes_used()); - - actions.set_action(LastBit::from(false)); - assert_eq!(2, actions.bytes_used()); -} - -#[test] -fn write_de_empty_actions() { - // The special case of no action bits set should still occupy one byte [of all zeroes]. - let de = ActionsDataElement::<Plaintext>::from(ActionBits::default()).to_de_bundle(); - - assert_eq!(&[0x00], de.contents_as_slice()); -} - -#[test] -fn write_de_one_action_byte() { - let mut action = ActionBits::default(); - action.set_action(ContextSyncSeqNum::try_from(7).unwrap()); - let de = ActionsDataElement::<Plaintext>::from(action).to_de_bundle(); - - assert_eq!(&[0x70], de.contents_as_slice()); -} - -#[test] -fn write_de_three_action_bytes() { - let mut action = ActionBits::default(); - action.set_action(LastBit::from(true)); - let de = ActionsDataElement::<Plaintext>::from(action).to_de_bundle(); - - assert_eq!(&[0, 0, 1], de.contents_as_slice()); -} - -#[test] -fn write_de_all_plaintext_actions() { - let mut action = all_plaintext_actions(); - action.set_action(LastBit::from(true)); - let de = ActionsDataElement::<Plaintext>::from(action).to_de_bundle(); - - // byte 0: context sync - // byte 1: nearby share, finder, fp sass - // byte 2: last bit - assert_eq!(&[0x90, 0x46, 0x01], de.contents_as_slice()); -} - -#[test] -fn write_de_all_encrypted_actions() { - let mut action = all_ciphertext_actions(); - action.set_action(LastBit::from(true)); - let de = ActionsDataElement::<Ciphertext>::from(action).to_de_bundle(); - - // byte 1: context sync num = 9, 4 unused bits - // byte 2: active unlock, nearby share, instant tethering, phone hub, - // presence manager, last 3 bits unused - // byte 3: last bit - assert_eq!(&[0x90, 0xF8, 0x01], de.contents_as_slice()); -} - -#[test] -fn action_element_nonzero_len() { - for t in ActionType::iter() { - assert!(t.bits_len() > 0); - } -} - -#[test] -fn action_element_bits_dont_overlap() { - let type_to_bits = - ActionType::iter().map(|t| (t, t.all_bits())).collect::<collections::HashMap<_, _>>(); - - for t in ActionType::iter() { - let bits = type_to_bits.get(&t).unwrap(); - - for (_, other_bits) in type_to_bits.iter().filter(|(other_type, _)| t != **other_type) { - assert_eq!(0, bits & other_bits, "type {t:?}"); - } - } -} - -#[test] -fn action_type_all_bits() { - assert_eq!(0xF0000000, ActionType::ContextSyncSeqNum.all_bits()); - assert_eq!(0x00800000, ActionType::ActiveUnlock.all_bits()); - assert_eq!(0x00020000, ActionType::FastPairSass.all_bits()); -} - -#[test] -fn action_type_all_bits_in_per_type_masks() { - for t in ActionType::iter().filter(|t| t.supports_flavor(PacketFlavorEnum::Plaintext)) { - assert_eq!(t.all_bits(), t.all_bits() & *ALL_PLAINTEXT_ELEMENT_BITS); - } - for t in ActionType::iter().filter(|t| t.supports_flavor(PacketFlavorEnum::Ciphertext)) { - assert_eq!(t.all_bits(), t.all_bits() & *ALL_CIPHERTEXT_ELEMENT_BITS); - } -} - -#[test] -fn action_bits_try_from_flavor_mismatch_plaintext() { - assert_eq!( - FlavorNotSupported { flavor: PacketFlavorEnum::Plaintext }, - ActionBits::<Plaintext>::try_from(ActionType::PresenceManager.all_bits()).unwrap_err() - ); - assert_eq!( - 0xF0000000, - ActionBits::<Plaintext>::try_from(ActionType::ContextSyncSeqNum.all_bits()).unwrap().bits - ); -} - -#[test] -fn actions_de_deser_plaintext_with_ciphertext_action() { - assert_eq!( - DataElementDeserializeError::FlavorNotSupported { - de_type: DataElementType::Actions, - flavor: PacketFlavorEnum::Plaintext - }, - <ActionsDataElement<Plaintext> as DataElement>::deserialize::<Plaintext>(&[ - // active unlock bit set - 0x00, 0x80, 0x00, - ]) - .unwrap_err() - ); -} - -#[test] -fn actions_de_deser_ciphertext_with_plaintext_action() { - assert_eq!( - DataElementDeserializeError::FlavorNotSupported { - de_type: DataElementType::Actions, - flavor: PacketFlavorEnum::Ciphertext - }, - <ActionsDataElement<Ciphertext> as DataElement>::deserialize::<Ciphertext>(&[ - // Finder bit set - 0x00, 0x00, 0x80, - ]) - .unwrap_err() - ); -} - -#[test] -fn context_sync_seq_num_works() { - let mut action_bits = ActionBits::<Plaintext>::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(15).unwrap()); - let action_de = ActionsDataElement::from(action_bits); - assert_eq!(15, action_de.action.context_sync_seq_num().as_u8()); -} - -#[test] -fn context_sync_seq_num_default_zero() { - let action_bits = ActionBits::<Plaintext>::default(); - let action_de = ActionsDataElement::from(action_bits); - assert_eq!(0, action_de.action.context_sync_seq_num().as_u8()); -} - -#[test] -fn has_action_plaintext_works() { - let mut action_bits = ActionBits::<Plaintext>::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(15).unwrap()); - action_bits.set_action(NearbyShare::from(true)); - let action_de = ActionsDataElement::from(action_bits); - assert_eq!(action_de.action.has_action(&ActionType::NearbyShare), Some(true)); - assert_eq!(action_de.action.has_action(&ActionType::ActiveUnlock), Some(false)); - assert_eq!(action_de.action.has_action(&ActionType::PhoneHub), Some(false)); -} - -#[test] -fn has_action_encrypted_works() { - let mut action_bits = ActionBits::<Ciphertext>::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(15).unwrap()); - action_bits.set_action(NearbyShare::from(true)); - action_bits.set_action(ActiveUnlock::from(true)); - let action_de = ActionsDataElement::from(action_bits); - assert_eq!(action_de.action.has_action(&ActionType::NearbyShare), Some(true)); - assert_eq!(action_de.action.has_action(&ActionType::ActiveUnlock), Some(true)); - assert_eq!(action_de.action.has_action(&ActionType::PhoneHub), Some(false)); - assert_eq!(action_de.action.has_action(&ActionType::ContextSyncSeqNum), None); -} - -// hypothetical action using the last bit -#[derive(Debug)] -struct LastBit { - enabled: bool, -} -impl From<bool> for LastBit { - fn from(value: bool) -> Self { - LastBit { enabled: value } - } -} -impl ActionElement for LastBit { - const HIGH_BIT_INDEX: u32 = 23; - const BITS_LEN: u32 = 1; - - // don't want to add a variant for this test only type - const ACTION_TYPE: ActionType = ActionType::ActiveUnlock; - - fn supports_flavor(_flavor: PacketFlavorEnum) -> bool { - true - } -} - -macros::boolean_element_to_plaintext_element!(LastBit); -macros::boolean_element_to_encrypted_element!(LastBit); - -fn assert_eq_hex(expected: u32, actual: u32) { - assert_eq!(expected, actual, "{expected:#010X} != {actual:#010X}"); -} - -pub(crate) fn all_plaintext_actions() -> ActionBits<Plaintext> { - let mut action = ActionBits::default(); - action.set_action(ContextSyncSeqNum::try_from(9).unwrap()); - action.set_action(NearbyShare::from(true)); - action.set_action(Finder::from(true)); - action.set_action(FastPairSass::from(true)); - action -} - -pub(crate) fn all_ciphertext_actions() -> ActionBits<Ciphertext> { - let mut action = ActionBits::default(); - action.set_action(ContextSyncSeqNum::try_from(9).unwrap()); - action.set_action(ActiveUnlock::from(true)); - action.set_action(NearbyShare::from(true)); - action.set_action(InstantTethering::from(true)); - action.set_action(PhoneHub::from(true)); - action.set_action(PresenceManager::from(true)); - action -}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements.rs b/nearby/presence/np_adv/src/legacy/data_elements.rs deleted file mode 100644 index c97cb25..0000000 --- a/nearby/presence/np_adv/src/legacy/data_elements.rs +++ /dev/null
@@ -1,143 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! V0 data elements and core trait impls. -use nom::error::{ErrorKind, FromExternalError}; - -use crate::legacy::{ - de_type::{DataElementType, PlainDataElementType}, - serialize::{DataElementBundle, ToDataElementBundle}, - PacketFlavor, PacketFlavorEnum, -}; -use crate::shared_data::*; - -/// Core behavior for data elements. -/// -/// See also [ToDataElementBundle] for flavor-specific, infallible serialization. -pub trait DataElement: Sized { - /// The corresponding DataElementType variant. - const DE_TYPE_VARIANT: DataElementType; - - /// Return true if the DE supports serialization and deserialization for the provided flavor. - fn supports_flavor(flavor: PacketFlavorEnum) -> bool; - - /// Returns `Err` if the flavor is not supported or if parsing fails. - /// - /// `<F>` is the flavor of the packet being deserialized. - fn deserialize<F: PacketFlavor>( - de_contents: &[u8], - ) -> Result<Self, DataElementDeserializeError>; -} - -/// Errors possible when deserializing a DE -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum DataElementDeserializeError { - /// The data element doesn't support the [PacketFlavor] of the advertisement packet. - FlavorNotSupported { - /// The DE type attempting to be deserialized - de_type: DataElementType, - /// The flavor that was not supported - flavor: PacketFlavorEnum, - }, - /// The data element couldn't be deserialized from the supplied data. - DeserializeError { - /// The DE type attempting to be deserialized - de_type: DataElementType, - }, - /// Only one identity data element is allowed in an advertisement, but a duplicate is found - /// while parsing. - DuplicateIdentityDataElement, - /// There is unexpected data remaining in the incoming payload. - UnexpectedDataRemaining, - /// Parsing error returned from Nom. - NomError(nom::error::ErrorKind), -} - -impl FromExternalError<&[u8], DataElementDeserializeError> for DataElementDeserializeError { - fn from_external_error( - _input: &[u8], - _kind: ErrorKind, - e: DataElementDeserializeError, - ) -> Self { - e - } -} - -impl nom::error::ParseError<&[u8]> for DataElementDeserializeError { - /// Creates an error from the input position and an [ErrorKind] - fn from_error_kind(_input: &[u8], kind: ErrorKind) -> Self { - Self::NomError(kind) - } - - /// Combines an existing error with a new one created from the input - /// position and an [ErrorKind]. This is useful when backtracking - /// through a parse tree, accumulating error context on the way - fn append(_input: &[u8], kind: ErrorKind, _other: Self) -> Self { - Self::NomError(kind) - } -} - -/// Data element holding a [TxPower]. -#[derive(Debug, PartialEq, Eq)] -pub struct TxPowerDataElement { - /// The tx power value - pub tx_power: TxPower, -} - -impl TxPowerDataElement { - /// Gets the underlying Tx Power value - pub fn tx_power_value(&self) -> i8 { - self.tx_power.as_i8() - } -} - -impl From<TxPower> for TxPowerDataElement { - fn from(tx_power: TxPower) -> Self { - Self { tx_power } - } -} - -impl<F: PacketFlavor> ToDataElementBundle<F> for TxPowerDataElement { - fn to_de_bundle(&self) -> DataElementBundle<F> { - let tx_power = self.tx_power.as_i8(); - DataElementBundle::try_from( - PlainDataElementType::TxPower, - tx_power.to_be_bytes().as_slice(), - ) - .expect("Length < max DE size") - } -} - -impl DataElement for TxPowerDataElement { - const DE_TYPE_VARIANT: DataElementType = DataElementType::TxPower; - - fn supports_flavor(flavor: PacketFlavorEnum) -> bool { - match flavor { - PacketFlavorEnum::Plaintext => true, - PacketFlavorEnum::Ciphertext => true, - } - } - fn deserialize<F: PacketFlavor>( - de_contents: &[u8], - ) -> Result<Self, DataElementDeserializeError> { - de_contents - .try_into() - .ok() - .and_then(|arr: [u8; 1]| TxPower::try_from(i8::from_be_bytes(arr)).ok()) - .map(|tx_power| Self { tx_power }) - .ok_or(DataElementDeserializeError::DeserializeError { - de_type: DataElementType::TxPower, - }) - } -}
diff --git a/nearby/presence/np_adv/src/legacy/actions/macros.rs b/nearby/presence/np_adv/src/legacy/data_elements/actions/macros.rs similarity index 64% rename from nearby/presence/np_adv/src/legacy/actions/macros.rs rename to nearby/presence/np_adv/src/legacy/data_elements/actions/macros.rs index db241d6..3d1ab48 100644 --- a/nearby/presence/np_adv/src/legacy/actions/macros.rs +++ b/nearby/presence/np_adv/src/legacy/data_elements/actions/macros.rs
@@ -38,9 +38,8 @@ macro_rules! boolean_element_action_element_impl_shared { ($type_name:ident, $index:expr) => { const HIGH_BIT_INDEX: u32 = $index; - const BITS_LEN: u32 = 1; - const ACTION_TYPE: $crate::legacy::actions::ActionType = - $crate::legacy::actions::ActionType::$type_name; + const ACTION_TYPE: $crate::legacy::data_elements::actions::ActionType = + $crate::legacy::data_elements::actions::ActionType::$type_name; }; } @@ -49,11 +48,11 @@ /// impls. macro_rules! boolean_element { ($type_name:ident, $index:expr, ciphertext_only) => { - $crate::legacy::actions::macros::boolean_element_struct!($type_name); - $crate::legacy::actions::macros::boolean_element_struct_from_bool!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_struct!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_struct_from_bool!($type_name); - impl $crate::legacy::actions::ActionElement for $type_name { - $crate::legacy::actions::macros::boolean_element_action_element_impl_shared!( + impl $crate::legacy::data_elements::actions::ActionElement for $type_name { + $crate::legacy::data_elements::actions::macros::boolean_element_action_element_impl_shared!( $type_name, $index ); @@ -63,16 +62,20 @@ $crate::legacy::PacketFlavorEnum::Ciphertext => true, } } + + fn bits(&self) -> u8 { + self.enabled as u8 + } } - $crate::legacy::actions::macros::boolean_element_to_encrypted_element!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_to_encrypted_element!($type_name); }; ($type_name:ident, $index:expr, plaintext_and_ciphertext) => { - $crate::legacy::actions::macros::boolean_element_struct!($type_name); - $crate::legacy::actions::macros::boolean_element_struct_from_bool!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_struct!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_struct_from_bool!($type_name); - impl $crate::legacy::actions::ActionElement for $type_name { - $crate::legacy::actions::macros::boolean_element_action_element_impl_shared!( + impl $crate::legacy::data_elements::actions::ActionElement for $type_name { + $crate::legacy::data_elements::actions::macros::boolean_element_action_element_impl_shared!( $type_name, $index ); @@ -82,31 +85,33 @@ $crate::legacy::PacketFlavorEnum::Ciphertext => true, } } + + fn bits(&self) -> u8 { + self.enabled as u8 + } } - $crate::legacy::actions::macros::boolean_element_to_plaintext_element!($type_name); - $crate::legacy::actions::macros::boolean_element_to_encrypted_element!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_to_plaintext_element!($type_name); + $crate::legacy::data_elements::actions::macros::boolean_element_to_encrypted_element!($type_name); }; } -/// Create a [`ToActionElement<Encrypted>`](super::ToActionElement) impl with the given index and length 1. +/// Create a [`ToActionElement<Encrypted>`](super::ActionElementFlavor) impl with the given index and length 1. macro_rules! boolean_element_to_encrypted_element { ( $type_name:ident) => { - impl $crate::legacy::actions::ToActionElement<$crate::legacy::Ciphertext> for $type_name { - fn bits(&self) -> u8 { - self.enabled as u8 - } + impl $crate::legacy::data_elements::actions::ActionElementFlavor<$crate::legacy::Ciphertext> + for $type_name + { } }; } -/// Create a [`ToActionElement<Plaintext>`](super::ToActionElement) impl with the given index and length 1. +/// Create a [`ToActionElement<Plaintext>`](super::ActionElementFlavor) impl with the given index and length 1. macro_rules! boolean_element_to_plaintext_element { ( $type_name:ident) => { - impl $crate::legacy::actions::ToActionElement<$crate::legacy::Plaintext> for $type_name { - fn bits(&self) -> u8 { - self.enabled as u8 - } + impl $crate::legacy::data_elements::actions::ActionElementFlavor<$crate::legacy::Plaintext> + for $type_name + { } }; }
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/actions/mod.rs b/nearby/presence/np_adv/src/legacy/data_elements/actions/mod.rs new file mode 100644 index 0000000..36ac35d --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/actions/mod.rs
@@ -0,0 +1,351 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The "Actions" data element and associated types. +//! +//! This DE is somewhat more complex than other DEs. Whether or not it supports a particular flavor +//! depends on the actions set, so it has to be treated as two separate types based on which +//! flavor type parameter is used. +use crate::legacy::data_elements::{DirectMapPredicate, DirectMapper, LengthMapper}; +use crate::{ + legacy::{ + data_elements::{ + de_type::{DeActualLength, DeEncodedLength, DeTypeCode}, + DataElementDeserializeError, DataElementSerializationBuffer, DataElementSerializeError, + DeserializeDataElement, SerializeDataElement, + }, + PacketFlavor, PacketFlavorEnum, + }, + private::Sealed, +}; + +#[cfg(feature = "devtools")] +use core::ops::Range; +use core::{marker, ops}; +use nom::{bytes, combinator, error}; +use sink::Sink; +use strum::IntoEnumIterator as _; + +mod macros; +#[cfg(test)] +pub(crate) mod tests; + +/// Actions DE. +/// Only as many DE payload bytes will be present as needed to represent all set bits that are encoded, +/// with a lower bound of 1 byte in the special case of no set action bits, and an upper bound +/// of 3 bytes occupied by the DE payload. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct ActionsDataElement<F: PacketFlavor> { + /// The action bits + pub action: ActionBits<F>, +} + +/// Max length of an actions DE contents +pub(crate) const ACTIONS_MAX_LEN: usize = 3; +/// Range of valid actual lengths +pub(crate) const ACTIONS_VALID_ACTUAL_LEN: ops::RangeInclusive<usize> = 1..=ACTIONS_MAX_LEN; + +impl<F> ActionsDataElement<F> +where + F: PacketFlavor, +{ + /// Generic deserialize, not meant to be called directly -- use [DeserializeDataElement] impls instead. + #[allow(clippy::assertions_on_constants)] + fn deserialize(de_contents: &[u8]) -> Result<Self, DataElementDeserializeError> { + combinator::all_consuming::<&[u8], _, error::Error<&[u8]>, _>(combinator::map( + bytes::complete::take_while_m_n(0, ACTIONS_MAX_LEN, |_| true), + |bytes: &[u8]| { + // pack bits into u32 for convenient access + debug_assert!(4 >= ACTIONS_MAX_LEN, "Actions must fit in u32"); + let mut action_bytes = [0_u8; 4]; + action_bytes[..bytes.len()].copy_from_slice(bytes); + u32::from_be_bytes(action_bytes) + }, + ))(de_contents) + .map_err(|_| DataElementDeserializeError::DeserializeError { de_type: Self::DE_TYPE_CODE }) + .map(|(_remaining, actions)| actions) + .and_then(|action_bits_num| { + let action = ActionBits::try_from(action_bits_num).map_err(|e| { + DataElementDeserializeError::FlavorNotSupported { + de_type: Self::DE_TYPE_CODE, + flavor: e.flavor, + } + })?; + Ok(Self { action }) + }) + } +} + +impl<F: PacketFlavor> From<ActionBits<F>> for ActionsDataElement<F> { + fn from(action: ActionBits<F>) -> Self { + Self { action } + } +} + +impl<F: PacketFlavor> Sealed for ActionsDataElement<F> {} + +impl<F: PacketFlavor> SerializeDataElement<F> for ActionsDataElement<F> { + fn de_type_code(&self) -> DeTypeCode { + ActionsDataElement::<F>::DE_TYPE_CODE + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + <Self as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual_len) + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + let used = self.action.bytes_used(); + sink.try_extend_from_slice(&self.action.bits.to_be_bytes()[..used]) + .ok_or(DataElementSerializeError::InsufficientSpace) + } +} + +impl<E: PacketFlavor> DeserializeDataElement for ActionsDataElement<E> { + const DE_TYPE_CODE: DeTypeCode = match DeTypeCode::try_from(0b0110) { + Ok(t) => t, + Err(_) => unreachable!(), + }; + + type LengthMapper = DirectMapper<ActionsLengthPredicate>; + + fn deserialize<F: PacketFlavor>( + de_contents: &[u8], + ) -> Result<Self, DataElementDeserializeError> { + if E::ENUM_VARIANT == F::ENUM_VARIANT { + ActionsDataElement::deserialize(de_contents) + } else { + Err(DataElementDeserializeError::FlavorNotSupported { + de_type: Self::DE_TYPE_CODE, + flavor: F::ENUM_VARIANT, + }) + } + } +} + +pub(in crate::legacy) struct ActionsLengthPredicate; + +impl DirectMapPredicate for ActionsLengthPredicate { + fn is_valid(len: usize) -> bool { + ACTIONS_VALID_ACTUAL_LEN.contains(&len) + } +} + +/// Container for the 24 bits defined for "actions" (feature flags and the like). +/// This internally stores a u32, but only the 24 highest bits of this +/// field will actually ever be populated. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct ActionBits<F: PacketFlavor> { + bits: u32, + // marker for element type + flavor: marker::PhantomData<F>, +} + +impl<F: PacketFlavor> ActionBits<F> { + /// Returns the actions bits as a u32. The upper limit of an actions field is 3 bytes, + /// so the last bytes of this u32 will always be 0 + pub fn as_u32(self) -> u32 { + self.bits + } + + /// Return whether a boolean action type is set in this data element, or `None` if the given + /// action type does not represent a boolean. + pub fn has_action(&self, action_type: ActionType) -> bool { + self.bits_for_type(action_type) != 0 + } +} + +impl<F: PacketFlavor> Default for ActionBits<F> { + fn default() -> Self { + ActionBits { + bits: 0, // no bits set + flavor: marker::PhantomData, + } + } +} + +/// At least one action doesn't support the required flavor +#[derive(PartialEq, Eq, Debug)] +pub struct FlavorNotSupported { + flavor: PacketFlavorEnum, +} + +lazy_static::lazy_static! { + /// All bits for plaintext action types: 1 where a plaintext action could have a bit, 0 elsewhere. + static ref ALL_PLAINTEXT_ELEMENT_BITS: u32 = ActionType::iter() + .filter(|t| t.supports_flavor(PacketFlavorEnum::Plaintext)) + .map(|t| t.all_bits()) + .fold(0_u32, |accum, bits| accum | bits); +} + +lazy_static::lazy_static! { + /// All bits for ciphertext action types: 1 where a ciphertext action could have a bit, 0 elsewhere. + static ref ALL_CIPHERTEXT_ELEMENT_BITS: u32 = ActionType::iter() + .filter(|t| t.supports_flavor(PacketFlavorEnum::Ciphertext)) + .map(|t| t.all_bits()) + .fold(0_u32, |accum, bits| accum | bits); +} + +impl<F: PacketFlavor> ActionBits<F> { + /// Tries to create ActionBits from a u32, returning error in the event a specific bit is set for + /// an unsupported flavor + pub fn try_from(value: u32) -> Result<Self, FlavorNotSupported> { + let ok_bits: u32 = match F::ENUM_VARIANT { + PacketFlavorEnum::Plaintext => *ALL_PLAINTEXT_ELEMENT_BITS, + PacketFlavorEnum::Ciphertext => *ALL_CIPHERTEXT_ELEMENT_BITS, + }; + + // no bits set beyond what's allowed for this flavor + if value | ok_bits == ok_bits { + Ok(Self { bits: value, flavor: marker::PhantomData }) + } else { + Err(FlavorNotSupported { flavor: F::ENUM_VARIANT }) + } + } + + /// Set the bits for the provided element. + /// Bits outside the range set by the action will be unaffected. + pub fn set_action<E: ActionElementFlavor<F>>(&mut self, action_element: E) { + let bits = action_element.bits(); + + // validate that the element is not horribly broken + debug_assert!(E::HIGH_BIT_INDEX < 32); + // must not have bits set past the low `len` bits + debug_assert_eq!(0, bits >> 1); + + // 0-extend to u32 + let byte_extended = bits as u32; + // Shift so that the high bit is at the desired index. + // Won't overflow since length > 0. + let bits_in_position = byte_extended << (31 - E::HIGH_BIT_INDEX); + + // We want to effectively clear out the bits already in place, so we don't want to just |=. + // Instead, we construct a u32 with all 1s above and below the relevant bits and &=, so that + // if the new bits are 0, the stored bits will be cleared. + + // avoid overflow when index = 0 -- need zero 1 bits to the left in that case + let left_1s = u32::MAX.checked_shl(32 - E::HIGH_BIT_INDEX).unwrap_or(0); + // avoid underflow when index + len = 32 -- zero 1 bits to the right + let right_1s = u32::MAX.checked_shr(E::HIGH_BIT_INDEX + 1).unwrap_or(0); + let mask = left_1s | right_1s; + let bits_for_other_actions = self.bits & mask; + self.bits = bits_for_other_actions | bits_in_position; + } + + /// How many bytes (1-3) are needed to represent the set bits, starting from the most + /// significant bit. The lower bound of 1 is because the unique special case of + /// an actions field of all zeroes is required by the spec to occupy exactly one byte. + fn bytes_used(&self) -> usize { + let bits_used = 32 - self.bits.trailing_zeros(); + let raw_count = (bits_used as usize + 7) / 8; + if raw_count == 0 { + 1 // Uncommon case - should only be hit for all-zero action bits + } else { + raw_count + } + } + + /// Return the bits for a given action type as the low bits in the returned u32. + /// + /// For example, when extracting the bits `B` from `0bXXXXXXXXXXBBBBBBXXXXXXXXXXXXXXXX`, the + /// return value will be `0b00000000000000000000000000BBBBBB`. + pub fn bits_for_type(&self, action_type: ActionType) -> u32 { + self.bits << action_type.high_bit_index() >> (31) + } +} + +/// Core trait for an individual action +pub trait ActionElement { + /// The assigned offset for this type from the high bit in the eventual bit sequence of all + /// actions. + /// + /// Each implementation must have a non-conflicting index defined by + /// [Self::HIGH_BIT_INDEX] + const HIGH_BIT_INDEX: u32; + + /// Forces implementations to have a matching enum variant so the enum can be kept up to date. + const ACTION_TYPE: ActionType; + + /// Returns whether this action supports the provided `flavor`. + /// + /// Must match the implementations of [ActionElementFlavor]. + fn supports_flavor(flavor: PacketFlavorEnum) -> bool; + + /// Returns the low bit that should be included in the final bit vector + /// starting at [Self::HIGH_BIT_INDEX]. + fn bits(&self) -> u8; +} + +/// Marker trait indicating support for a particular [PacketFlavor]. +pub trait ActionElementFlavor<F: PacketFlavor>: ActionElement {} + +/// Provides a way to iterate over all action types. +#[derive(Clone, Copy, strum_macros::EnumIter, PartialEq, Eq, Hash, Debug)] +#[allow(missing_docs)] +pub enum ActionType { + CrossDevSdk, + CallTransfer, + ActiveUnlock, + NearbyShare, + InstantTethering, + PhoneHub, +} + +impl ActionType { + /// A u32 with all possible bits for this action type set + const fn all_bits(&self) -> u32 { + (u32::MAX << (31_u32)) >> self.high_bit_index() + } + + /// Get the range of the bits occupied used by this bit index. For example, if the action type + /// uses the 5th and 6th bits, the returned range will be (5..7). + /// (0 is the index of the most significant bit). + #[cfg(feature = "devtools")] + pub const fn bits_range_for_devtools(&self) -> Range<u32> { + let high_bit_index = self.high_bit_index(); + high_bit_index..high_bit_index + 1 + } + + const fn high_bit_index(&self) -> u32 { + match self { + ActionType::CrossDevSdk => CrossDevSdk::HIGH_BIT_INDEX, + ActionType::CallTransfer => CallTransfer::HIGH_BIT_INDEX, + ActionType::ActiveUnlock => ActiveUnlock::HIGH_BIT_INDEX, + ActionType::NearbyShare => NearbyShare::HIGH_BIT_INDEX, + ActionType::InstantTethering => InstantTethering::HIGH_BIT_INDEX, + ActionType::PhoneHub => PhoneHub::HIGH_BIT_INDEX, + } + } + + pub(crate) fn supports_flavor(&self, flavor: PacketFlavorEnum) -> bool { + match self { + ActionType::CrossDevSdk => CrossDevSdk::supports_flavor(flavor), + ActionType::CallTransfer => CallTransfer::supports_flavor(flavor), + ActionType::ActiveUnlock => ActiveUnlock::supports_flavor(flavor), + ActionType::NearbyShare => NearbyShare::supports_flavor(flavor), + ActionType::InstantTethering => InstantTethering::supports_flavor(flavor), + ActionType::PhoneHub => PhoneHub::supports_flavor(flavor), + } + } +} + +// enabling an element for public adv requires privacy approval due to fingerprinting risk +macros::boolean_element!(CrossDevSdk, 1, plaintext_and_ciphertext); +macros::boolean_element!(CallTransfer, 4, ciphertext_only); +macros::boolean_element!(ActiveUnlock, 8, ciphertext_only); +macros::boolean_element!(NearbyShare, 9, plaintext_and_ciphertext); +macros::boolean_element!(InstantTethering, 10, ciphertext_only); +macros::boolean_element!(PhoneHub, 11, ciphertext_only);
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/actions/tests.rs b/nearby/presence/np_adv/src/legacy/data_elements/actions/tests.rs new file mode 100644 index 0000000..b96f94a --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/actions/tests.rs
@@ -0,0 +1,690 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use crate::{ + legacy::{ + data_elements::{ + actions::{self, *}, + tests::macros::de_roundtrip_test, + }, + serialize::encode_de_header, + serialize::tests::serialize, + Ciphertext, Plaintext, + }, + DeLengthOutOfRange, +}; +use rand::seq::SliceRandom; +use rand::Rng; +use std::collections; +use std::panic; +use std::prelude::rust_2021::*; + +#[test] +fn setting_action_only_changes_that_actions_bits() { + fn do_test<F: PacketFlavor>( + set_ones: impl Fn(ActionType, &mut ActionBits<F>), + set_zeros: impl Fn(ActionType, &mut ActionBits<F>), + ) { + for t in supported_action_types(F::ENUM_VARIANT) { + let other_types = supported_action_types(F::ENUM_VARIANT) + .into_iter() + .filter(|t2| *t2 != t) + .collect::<Vec<_>>(); + + let mut actions = ActionBits::<F>::default(); + set_ones(t, &mut actions); + + // only the correct bits are set internally + assert_eq!(t.all_bits(), actions.as_u32()); + // we can extract those bits + assert_eq!(t.all_bits() >> (31 - t.high_bit_index()), actions.bits_for_type(t)); + // consider context sync (None) to be "set" for our purposes + assert!(actions.has_action(t)); + // other types aren't set + for &t2 in &other_types { + assert_eq!(0, actions.bits_for_type(t2)) + } + + // now check that unsetting works + actions.bits = u32::MAX; + set_zeros(t, &mut actions); + + assert_eq!(!t.all_bits(), actions.as_u32()); + assert_eq!(0, actions.bits_for_type(t)); + assert!(!actions.has_action(t)); + // other types are set + for &t2 in &other_types { + assert_eq!(t2.all_bits() >> (31 - t2.high_bit_index()), actions.bits_for_type(t2)); + } + } + } + + do_test( + |t, bits| set_plaintext_action(t, true, bits), + |t, bits| set_plaintext_action(t, false, bits), + ); + do_test( + |t, bits| set_ciphertexttext_action(t, true, bits), + |t, bits| set_ciphertexttext_action(t, false, bits), + ); +} + +#[test] +fn random_combos_of_actions_have_correct_bits_set() { + fn do_test<F: PacketFlavor>(set_ones: impl Fn(ActionType, &mut ActionBits<F>)) { + let all_types = supported_action_types(F::ENUM_VARIANT); + let mut rng = rand::thread_rng(); + + for _ in 0..1000 { + let len = rng.gen_range(0..=all_types.len()); + let selected = all_types.choose_multiple(&mut rng, len).copied().collect::<Vec<_>>(); + let not_selected = + all_types.iter().filter(|t| !selected.contains(t)).copied().collect::<Vec<_>>(); + + let mut actions = ActionBits::<F>::default(); + for &t in &selected { + set_ones(t, &mut actions); + } + + for &t in &selected { + assert_ne!(0, actions.bits_for_type(t)); + } + for &t in ¬_selected { + assert_eq!(0, actions.bits_for_type(t)); + } + + assert_eq!(selected.iter().fold(0, |accum, t| accum | t.all_bits()), actions.bits); + } + } + + do_test::<Plaintext>(|t, bits| set_plaintext_action(t, true, bits)); + do_test::<Ciphertext>(|t, bits| set_ciphertexttext_action(t, true, bits)); +} + +#[test] +fn set_last_bit_works() { + let mut actions = ActionBits::<Plaintext>::default(); + + actions.set_action(LastBit::from(true)); + assert_eq_hex(0x0100, actions.bits); +} + +#[test] +fn set_last_bit_doesnt_clobber_others() { + let mut actions = ActionBits::<Plaintext>::default(); + + // set neighboring bits + actions.bits |= 0x200; + + actions.set_action(LastBit::from(true)); + assert_eq_hex(0x300, actions.bits); +} + +#[test] +fn unset_last_bit_works() { + let mut actions = ActionBits::<Plaintext> { + // all 1s + bits: u32::MAX, + ..Default::default() + }; + + actions.set_action(LastBit::from(false)); + assert_eq_hex(0xFFFFFEFF, actions.bits); +} + +#[test] +fn bytes_used_works() { + let mut actions = ActionBits::<Plaintext>::default(); + + // Special-case: All-zeroes should lead to a single byte being used. + assert_eq!(1, actions.bytes_used()); + + actions.set_action(NearbyShare::from(true)); + assert_eq!(2, actions.bytes_used()); + + actions.set_action(LastBit::from(true)); + assert_eq!(3, actions.bytes_used()); + + actions.set_action(LastBit::from(false)); + assert_eq!(2, actions.bytes_used()); +} + +#[test] +fn write_de_empty_actions() { + // The special case of no action bits set should still occupy one byte [of all zeroes]. + + assert_eq!( + &[actions_de_header_byte(1), 0x00], + serialize(&ActionsDataElement::<Plaintext>::from(ActionBits::default())).as_slice() + ); +} + +#[test] +fn write_de_one_action_byte() { + let mut action = ActionBits::default(); + action.set_action(FirstBit::from(true)); + + assert_eq!( + &[actions_de_header_byte(1), 0b1000_0000], + serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice() + ); +} + +#[test] +fn write_de_three_action_bytes() { + let mut action = ActionBits::default(); + action.set_action(LastBit::from(true)); + + assert_eq!( + &[actions_de_header_byte(3), 0, 0, 1], + serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice() + ); +} + +#[test] +fn write_de_all_plaintext_actions() { + let mut action = all_plaintext_actions_set(); + action.set_action(LastBit::from(true)); + + // byte 0: cross dev sdk = 1 + // byte 1: nearby share + // byte 2: last bit + assert_eq!( + &[actions_de_header_byte(3), 0x40, 0x40, 0x01], + serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice() + ); +} + +#[test] +fn write_de_all_encrypted_actions() { + let mut action = all_ciphertext_actions_set(); + action.set_action(LastBit::from(true)); + + // byte 1: cross dev sdk = 1, call transfer = 4 + // byte 2: active unlock, nearby share, instant tethering, phone hub, + // byte 3: last bit + assert_eq!( + &[actions_de_header_byte(3), 0x48, 0xF0, 0x01], + serialize(&ActionsDataElement::<Ciphertext>::from(action)).as_slice() + ); +} + +#[test] +fn roundtrip_de_random_action_combos() { + fn do_test<F>(set_ones: impl Fn(ActionType, &mut ActionBits<F>)) + where + F: PacketFlavor, + ActionsDataElement<F>: DeserializeDataElement, + { + let all_types = supported_action_types(F::ENUM_VARIANT); + let mut rng = rand::thread_rng(); + + for _ in 0..1000 { + let len = rng.gen_range(0..=all_types.len()); + let selected = all_types.choose_multiple(&mut rng, len).copied().collect::<Vec<_>>(); + + let mut actions = ActionBits::<F>::default(); + for &t in &selected { + set_ones(t, &mut actions); + } + + let de = ActionsDataElement::<F>::from(actions); + let serialized = serialize(&de); + // skip header + let contents = &serialized.as_slice()[1..]; + let deserialized = ActionsDataElement::<F>::deserialize(contents).unwrap(); + + assert_eq!(de.action, deserialized.action); + } + } + + do_test::<Plaintext>(|t, bits| set_plaintext_action(t, true, bits)); + do_test::<Ciphertext>(|t, bits| set_ciphertexttext_action(t, true, bits)); +} + +#[test] +fn action_element_bits_dont_overlap() { + let type_to_bits = + ActionType::iter().map(|t| (t, t.all_bits())).collect::<collections::HashMap<_, _>>(); + + for t in ActionType::iter() { + let bits = type_to_bits.get(&t).unwrap(); + + for (_, other_bits) in type_to_bits.iter().filter(|(other_type, _)| t != **other_type) { + assert_eq!(0, bits & other_bits, "type {t:?}"); + } + } +} + +#[test] +fn action_type_all_bits_masks() { + assert_eq!(0x08000000, ActionType::CallTransfer.all_bits()); + assert_eq!(0x00800000, ActionType::ActiveUnlock.all_bits()); + assert_eq!(0x00400000, ActionType::NearbyShare.all_bits()); + assert_eq!(0x00200000, ActionType::InstantTethering.all_bits()); + assert_eq!(0x00100000, ActionType::PhoneHub.all_bits()); +} + +#[test] +fn action_type_all_bits_in_per_type_masks() { + for t in supported_action_types(PacketFlavorEnum::Plaintext) { + assert_eq!(t.all_bits(), t.all_bits() & *ALL_PLAINTEXT_ELEMENT_BITS); + } + for t in supported_action_types(PacketFlavorEnum::Ciphertext) { + assert_eq!(t.all_bits(), t.all_bits() & *ALL_CIPHERTEXT_ELEMENT_BITS); + } +} + +#[test] +fn action_bits_try_from_flavor_mismatch_plaintext() { + assert_eq!( + FlavorNotSupported { flavor: PacketFlavorEnum::Plaintext }, + ActionBits::<Plaintext>::try_from(ActionType::CallTransfer.all_bits()).unwrap_err() + ); +} + +#[test] +fn actions_de_deser_plaintext_with_ciphertext_action() { + assert_eq!( + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Plaintext, + }, + <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Plaintext>(&[ + // active unlock bit set + 0x00, 0x80, 0x00, + ]) + .unwrap_err() + ); +} + +#[test] +fn actions_de_deser_ciphertext_with_plaintext_action() { + assert_eq!( + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Ciphertext, + }, + <ActionsDataElement<Ciphertext> as DeserializeDataElement>::deserialize::<Ciphertext>(&[ + // Finder bit set + 0x00, 0x00, 0x80, + ]) + .unwrap_err() + ); +} + +#[test] +fn actions_de_deser_plaintext_with_ciphertext_error() { + assert_eq!( + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Plaintext, + }, + <ActionsDataElement<Ciphertext> as DeserializeDataElement>::deserialize::<Plaintext>(&[ + 0x00 + ]) + .unwrap_err() + ); +} + +#[test] +fn actions_de_deser_ciphertext_with_plaintext_error() { + assert_eq!( + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Ciphertext, + }, + <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Ciphertext>(&[ + 0x00 + ]) + .unwrap_err() + ); +} + +#[test] +fn deserialize_content_too_long_error() { + assert_eq!( + DataElementDeserializeError::DeserializeError { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE + }, + <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Plaintext>( + &[0x00; 10] + ) + .unwrap_err() + ); +} + +#[test] +fn actions_min_len_unencrypted() { + let actions = ActionBits::<Plaintext>::default(); + + let (_de, ser) = de_roundtrip_test!( + ActionsDataElement<Plaintext>, + Actions, + Actions, + Plaintext, + serialize(&actions::ActionsDataElement::from(actions)) + ); + + assert_eq!( + &[ + encode_de_header( + ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + DeEncodedLength::from(1), + ), + 0 + ], + ser.as_slice() + ); +} + +#[test] +fn actions_min_len_ldt() { + let actions = ActionBits::<Ciphertext>::default(); + + let (_de, ser) = de_roundtrip_test!( + ActionsDataElement<Ciphertext>, + Actions, + Actions, + Ciphertext, + serialize(&actions::ActionsDataElement::from(actions)) + ); + + // header and 1 DE contents byte + assert_eq!(2, ser.as_slice().len()); +} + +#[test] +fn actions_de_contents_normal_actions_roundtrip_unencrypted() { + let actions = all_plaintext_actions_set(); + + let _ = de_roundtrip_test!( + ActionsDataElement<Plaintext>, + Actions, + Actions, + Plaintext, + serialize(&actions::ActionsDataElement::from(actions)) + ); +} + +#[test] +fn actions_de_contents_normal_actions_roundtrip_ldt() { + let actions = all_ciphertext_actions_set(); + + let _ = de_roundtrip_test!( + ActionsDataElement<Ciphertext>, + Actions, + Actions, + Ciphertext, + serialize(&actions::ActionsDataElement::from(actions)) + ); +} + +#[test] +fn has_action_plaintext_works() { + let mut action_bits = ActionBits::<Plaintext>::default(); + action_bits.set_action(NearbyShare::from(true)); + let action_de = ActionsDataElement::from(action_bits); + assert!(action_de.action.has_action(ActionType::NearbyShare)); + assert!(!action_de.action.has_action(ActionType::ActiveUnlock)); + assert!(!action_de.action.has_action(ActionType::PhoneHub)); +} + +#[test] +fn has_action_encrypted_works() { + let mut action_bits = ActionBits::<Ciphertext>::default(); + action_bits.set_action(NearbyShare::from(true)); + action_bits.set_action(ActiveUnlock::from(true)); + let action_de = ActionsDataElement::from(action_bits); + assert!(action_de.action.has_action(ActionType::NearbyShare)); + assert!(action_de.action.has_action(ActionType::ActiveUnlock)); + assert!(!action_de.action.has_action(ActionType::PhoneHub)); +} + +#[test] +fn actual_length_must_be_in_range() { + let de = ActionsDataElement::<Plaintext>::from(ActionBits::default()); + + for l in [0, ACTIONS_MAX_LEN + 1] { + let actual = DeActualLength::try_from(l).unwrap(); + let _ = panic::catch_unwind(|| de.map_actual_len_to_encoded_len(actual)).unwrap_err(); + } + + for l in ACTIONS_VALID_ACTUAL_LEN { + assert_eq!( + l, + de.map_actual_len_to_encoded_len(DeActualLength::try_from(l).unwrap()).as_usize() + ) + } +} + +#[test] +fn encoded_length_must_be_in_range() { + for l in [0, ACTIONS_MAX_LEN + 1] { + assert_eq!( + DeLengthOutOfRange, + <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len( + DeEncodedLength::try_from(l as u8).unwrap() + ) + .unwrap_err() + ) + } + + for l in ACTIONS_VALID_ACTUAL_LEN { + assert_eq!( + l, + <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len( + DeEncodedLength::try_from(l as u8).unwrap() + ) + .unwrap() + .as_usize() + ); + } +} + +mod coverage_gaming { + use crate::legacy::data_elements::actions::*; + use crate::legacy::Plaintext; + use alloc::format; + + #[test] + fn actions_de_debug() { + let actions = ActionsDataElement::<Plaintext>::from(ActionBits::default()); + let _ = format!("{:?}", actions); + } + + #[test] + fn flavor_not_supported_debug() { + let _ = format!("{:?}", FlavorNotSupported { flavor: PacketFlavorEnum::Plaintext }); + } + + #[test] + fn action_type_clone_debug() { + let _ = format!("{:?}", ActionType::CallTransfer.clone()); + } + + #[test] + fn actions_debug() { + let _ = format!("{:?}", CallTransfer::from(true)); + let _ = format!("{:?}", ActiveUnlock::from(true)); + let _ = format!("{:?}", NearbyShare::from(true)); + let _ = format!("{:?}", InstantTethering::from(true)); + let _ = format!("{:?}", PhoneHub::from(true)); + } +} + +// Test only action which uses the first bit +#[derive(Debug)] +pub(crate) struct FirstBit { + enabled: bool, +} + +impl From<bool> for FirstBit { + fn from(value: bool) -> Self { + FirstBit { enabled: value } + } +} + +impl ActionElement for FirstBit { + const HIGH_BIT_INDEX: u32 = 0; + // don't want to add a variant for this test only type + const ACTION_TYPE: ActionType = ActionType::ActiveUnlock; + + fn supports_flavor(_flavor: PacketFlavorEnum) -> bool { + true + } + + fn bits(&self) -> u8 { + self.enabled as u8 + } +} + +macros::boolean_element_to_plaintext_element!(FirstBit); +macros::boolean_element_to_encrypted_element!(FirstBit); + +// hypothetical action using the last bit +#[derive(Debug)] +pub(crate) struct LastBit { + enabled: bool, +} + +impl From<bool> for LastBit { + fn from(value: bool) -> Self { + LastBit { enabled: value } + } +} + +impl ActionElement for LastBit { + const HIGH_BIT_INDEX: u32 = 23; + // don't want to add a variant for this test only type + const ACTION_TYPE: ActionType = ActionType::ActiveUnlock; + + fn supports_flavor(_flavor: PacketFlavorEnum) -> bool { + true + } + + fn bits(&self) -> u8 { + self.enabled as u8 + } +} + +macros::boolean_element_to_plaintext_element!(LastBit); +macros::boolean_element_to_encrypted_element!(LastBit); + +// An action that only supports plaintext, to allow testing that error case +pub(in crate::legacy) struct PlaintextOnly { + enabled: bool, +} + +impl From<bool> for PlaintextOnly { + fn from(value: bool) -> Self { + Self { enabled: value } + } +} + +impl ActionElement for PlaintextOnly { + const HIGH_BIT_INDEX: u32 = 22; + + const ACTION_TYPE: ActionType = ActionType::ActiveUnlock; + + fn supports_flavor(flavor: PacketFlavorEnum) -> bool { + match flavor { + PacketFlavorEnum::Plaintext => true, + PacketFlavorEnum::Ciphertext => false, + } + } + + fn bits(&self) -> u8 { + self.enabled as u8 + } +} + +macros::boolean_element_to_plaintext_element!(PlaintextOnly); +// sneakily allow serializing it, but deserializing will fail due to supports_flavor above +macros::boolean_element_to_encrypted_element!(PlaintextOnly); + +fn assert_eq_hex(expected: u32, actual: u32) { + assert_eq!(expected, actual, "{expected:#010X} != {actual:#010X}"); +} + +pub(crate) fn all_plaintext_actions_set() -> ActionBits<Plaintext> { + let mut action = ActionBits::default(); + action.set_action(CrossDevSdk::from(true)); + action.set_action(NearbyShare::from(true)); + + assert!(supported_action_types(PacketFlavorEnum::Plaintext) + .into_iter() + .all(|t| t.all_bits() & action.bits != 0)); + + action +} + +pub(crate) fn all_ciphertext_actions_set() -> ActionBits<Ciphertext> { + let mut action = ActionBits::default(); + action.set_action(CrossDevSdk::from(true)); + action.set_action(CallTransfer::from(true)); + action.set_action(ActiveUnlock::from(true)); + action.set_action(NearbyShare::from(true)); + action.set_action(InstantTethering::from(true)); + action.set_action(PhoneHub::from(true)); + + assert!(supported_action_types(PacketFlavorEnum::Ciphertext) + .into_iter() + .all(|t| t.all_bits() & action.bits != 0)); + + action +} + +fn supported_action_types(flavor: PacketFlavorEnum) -> Vec<ActionType> { + ActionType::iter().filter(|t| t.supports_flavor(flavor)).collect() +} + +/// Encode a DE header byte with the provided type and actual len, transforming into an encoded +/// len appropriately. +fn actions_de_header_byte(actual_len: u8) -> u8 { + encode_de_header( + ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + DeEncodedLength::try_from(actual_len).unwrap(), + ) +} + +pub(crate) fn set_plaintext_action(t: ActionType, value: bool, bits: &mut ActionBits<Plaintext>) { + match t { + ActionType::CrossDevSdk => bits.set_action(CrossDevSdk::from(value)), + ActionType::NearbyShare => bits.set_action(NearbyShare::from(value)), + ActionType::CallTransfer + | ActionType::PhoneHub + | ActionType::ActiveUnlock + | ActionType::InstantTethering => panic!(), + } +} + +pub(crate) fn set_ciphertexttext_action( + t: ActionType, + value: bool, + bits: &mut ActionBits<Ciphertext>, +) { + match t { + ActionType::CrossDevSdk => bits.set_action(CrossDevSdk::from(value)), + ActionType::CallTransfer => bits.set_action(CallTransfer::from(value)), + ActionType::ActiveUnlock => bits.set_action(ActiveUnlock::from(value)), + ActionType::NearbyShare => bits.set_action(NearbyShare::from(value)), + ActionType::InstantTethering => bits.set_action(InstantTethering::from(value)), + ActionType::PhoneHub => bits.set_action(PhoneHub::from(value)), + } +}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/de_type/mod.rs b/nearby/presence/np_adv/src/legacy/data_elements/de_type/mod.rs new file mode 100644 index 0000000..e5dd153 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/de_type/mod.rs
@@ -0,0 +1,127 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! V0 data element types. +//! +//! In V0, there are only 16 DE types total, and parsing unknown types is not possible, so we can +//! represent all known DE types in enums without needing to handle the "unknown type" case. + +use crate::{legacy::NP_MAX_DE_CONTENT_LEN, DeLengthOutOfRange}; +use strum_macros::EnumIter; + +#[cfg(test)] +mod tests; + +/// A V0 DE type in `[0, 15]`. +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct DeTypeCode { + /// The code used in a V0 adv header + code: u8, +} + +impl DeTypeCode { + /// Returns a u8 in `[0, 15`]. + pub(crate) fn as_u8(&self) -> u8 { + self.code + } + + pub(crate) const fn try_from(value: u8) -> Result<Self, DeTypeCodeOutOfRange> { + if value < 16 { + Ok(Self { code: value }) + } else { + Err(DeTypeCodeOutOfRange) + } + } +} + +/// The DE type code is out of range for v0 DE types. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub(crate) struct DeTypeCodeOutOfRange; + +/// The actual length of a DE's contents, not the encoded representation. +/// +/// See [DeEncodedLength] for the encoded length. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DeActualLength { + /// Invariant: <= [NP_MAX_DE_CONTENT_LEN]. + len: u8, +} + +impl DeActualLength { + pub(crate) fn try_from(value: usize) -> Result<Self, DeLengthOutOfRange> { + if value <= NP_MAX_DE_CONTENT_LEN { + Ok(Self { len: value as u8 }) + } else { + Err(DeLengthOutOfRange) + } + } + + pub(crate) fn as_u8(&self) -> u8 { + self.len + } + + pub(crate) fn as_usize(&self) -> usize { + self.len.into() + } +} + +/// Maximum encoded length value +pub(crate) const MAX_DE_ENCODED_LEN: u8 = 15; + +/// The encoded length of a DE, not the actual length of the DE contents. +/// +/// See [DeActualLength] for the length of the contents. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DeEncodedLength { + /// Invariant: `len <= 0x0F` (15, aka 4 bits) + len: u8, +} + +impl DeEncodedLength { + pub(crate) fn try_from(value: u8) -> Result<Self, DeLengthOutOfRange> { + if value <= MAX_DE_ENCODED_LEN { + Ok(Self { len: value }) + } else { + Err(DeLengthOutOfRange) + } + } + + /// Test-only helper that panics for less unwrapping in tests. + /// + /// # Panics + /// + /// Panics if `value` is invalid. + #[cfg(test)] + pub(in crate::legacy) fn from(value: u8) -> Self { + Self::try_from(value).expect("Invalid len") + } + + /// Returns a u8 in `[0, 15]` + pub(crate) fn as_u8(&self) -> u8 { + self.len + } + + /// Returns a usize in `[0, 15]` + pub(crate) fn as_usize(&self) -> usize { + self.len as usize + } +} + +/// Corresponds to the normal data element types. +#[derive(EnumIter, Debug, Clone, Copy, PartialEq, Eq)] +#[allow(missing_docs)] +pub(in crate::legacy) enum DataElementType { + TxPower, + Actions, +}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/de_type/tests.rs b/nearby/presence/np_adv/src/legacy/data_elements/de_type/tests.rs new file mode 100644 index 0000000..72c8482 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/de_type/tests.rs
@@ -0,0 +1,153 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use super::*; +use crate::legacy::data_elements::{DeserializeDataElement, LengthMapper}; +use crate::legacy::serialize::tests::helpers::{LongDataElement, ShortDataElement}; +use crate::legacy::{Ciphertext, PacketFlavor}; +use crate::{ + legacy::{ + data_elements::{ + actions::{ActionBits, ActionsDataElement}, + tx_power::TxPowerDataElement, + SerializeDataElement, + }, + Plaintext, + }, + shared_data::TxPower, +}; +use alloc::vec; +use core::panic::{RefUnwindSafe, UnwindSafe}; +use std::{collections, panic}; + +#[test] +fn de_type_code_in_range_ok() { + assert_eq!(3, DeTypeCode::try_from(3).unwrap().code); +} + +#[test] +fn de_type_code_out_of_range_err() { + assert_eq!(DeTypeCodeOutOfRange, DeTypeCode::try_from(30).unwrap_err()); +} + +#[test] +fn de_actual_length_in_range_ok() { + assert_eq!(3, DeActualLength::try_from(3).unwrap().len); +} + +#[test] +fn de_actual_length_out_of_range_err() { + assert_eq!( + DeLengthOutOfRange, + DeActualLength::try_from(NP_MAX_DE_CONTENT_LEN + 1).unwrap_err() + ); +} + +#[test] +fn de_encoded_length_in_range_ok() { + assert_eq!(3, DeEncodedLength::from(3).len); +} + +#[test] +fn de_encoded_length_out_of_range_err() { + assert_eq!(DeLengthOutOfRange, DeEncodedLength::try_from(MAX_DE_ENCODED_LEN + 1).unwrap_err()); +} + +#[test] +fn de_length_actual_encoded_round_trip() { + fn do_de_length_test< + F: PacketFlavor, + D: DeserializeDataElement + SerializeDataElement<F> + UnwindSafe + RefUnwindSafe, + >( + de: D, + ) { + // for all possible lengths, calculate actual -> encoded and the inverse + let actual_to_encoded = (0_u8..=255) + .filter_map(|num| DeActualLength::try_from(usize::from(num)).ok()) + .filter_map(|actual: DeActualLength| { + panic::catch_unwind(|| de.map_actual_len_to_encoded_len(actual)) + .ok() + .map(|encoded| (actual, encoded)) + }) + .collect::<collections::HashMap<_, _>>(); + + let encoded_to_actual = (0_u8..=255) + .filter_map(|num| DeEncodedLength::try_from(num).ok()) + .filter_map(|encoded: DeEncodedLength| { + D::LengthMapper::map_encoded_len_to_actual_len(encoded) + .ok() + .map(|actual| (encoded, actual)) + }) + .collect::<collections::HashMap<_, _>>(); + + // ensure the two maps are inverses of each other + assert_eq!( + actual_to_encoded, + encoded_to_actual.into_iter().map(|(encoded, actual)| (actual, encoded)).collect(), + ); + } + + do_de_length_test::<Plaintext, _>(TxPowerDataElement::from(TxPower::try_from(1).unwrap())); + do_de_length_test(ActionsDataElement::<Plaintext>::from(ActionBits::default())); + do_de_length_test(ActionsDataElement::<Ciphertext>::from(ActionBits::default())); + + // might as well make sure our test DEs behave as well + do_de_length_test::<Plaintext, _>(ShortDataElement::new(vec![])); + do_de_length_test::<Plaintext, _>(LongDataElement::new(vec![])); +} + +mod coverage_gaming { + use crate::legacy::data_elements::de_type::{ + DataElementType, DeActualLength, DeEncodedLength, DeTypeCode, DeTypeCodeOutOfRange, + }; + + extern crate std; + + use std::{collections, format}; + + #[test] + fn de_type_code_debug_hash_clone() { + let code = DeTypeCode::try_from(3).unwrap(); + let _ = format!("{:?}", code.clone()); + let _ = collections::HashSet::from([code]); + } + + #[test] + fn de_type_code_out_of_range() { + // debug, clone + let _ = format!("{:?}", DeTypeCodeOutOfRange.clone()); + } + + #[test] + fn de_actual_length() { + // debug, clone + let _ = format!("{:?}", DeActualLength::try_from(3).unwrap().clone()); + } + + #[test] + fn de_encoded_length() { + // debug, clone + let _ = format!("{:?}", DeEncodedLength::from(3).clone()); + } + + #[test] + fn de_type() { + // debug, clone + let _ = format!("{:?}", DataElementType::TxPower.clone()); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/mod.rs b/nearby/presence/np_adv/src/legacy/data_elements/mod.rs new file mode 100644 index 0000000..5dd0587 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/mod.rs
@@ -0,0 +1,266 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! V0 data elements and core trait impls. + +use crate::{ + extended::serialize::CapacityLimitedVec, + legacy::{ + data_elements::de_type::{DeActualLength, DeEncodedLength, DeTypeCode}, + PacketFlavor, PacketFlavorEnum, NP_MAX_ADV_CONTENT_LEN, + }, + private::Sealed, + DeLengthOutOfRange, +}; +use core::marker; +use nom::error::{self}; +use sink::Sink; + +pub mod actions; +pub mod de_type; +pub mod tx_power; + +#[cfg(test)] +pub(in crate::legacy) mod tests; + +/// Deserialization for a specific data element type. +/// +/// See also [SerializeDataElement] for flavor-specific, infallible serialization. +pub(in crate::legacy) trait DeserializeDataElement: Sized + Sealed { + const DE_TYPE_CODE: DeTypeCode; + + /// Define how length mapping is done for this DE type + type LengthMapper: LengthMapper; + + /// Deserialize `Self` from the provided DE contents (not including the + /// DE header). + /// + /// Returns `Err` if the flavor is not supported or if parsing fails. + /// + /// `<F>` is the flavor of the packet being deserialized. + fn deserialize<F: PacketFlavor>( + de_contents: &[u8], + ) -> Result<Self, DataElementDeserializeError>; +} + +/// Errors possible when deserializing a DE +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum DataElementDeserializeError { + /// The data element doesn't support the [PacketFlavor] of the advertisement packet. + FlavorNotSupported { + /// The DE type attempting to be deserialized + de_type: DeTypeCode, + /// The flavor that was not supported + flavor: PacketFlavorEnum, + }, + /// The data element couldn't be deserialized from the supplied data. + DeserializeError { + /// The DE type attempting to be deserialized + de_type: DeTypeCode, + }, + /// Invalid DE type + InvalidDeType { + /// The unknown type + de_type: DeTypeCode, + }, + /// Invalid DE length + InvalidDeLength { + /// The DE type attempting to be deserialized + de_type: DeTypeCode, + /// The invalid length + len: DeEncodedLength, + }, + /// Other parse error, e.g. the adv is truncated + InvalidStructure, +} + +impl error::FromExternalError<&[u8], DataElementDeserializeError> for DataElementDeserializeError { + fn from_external_error( + _input: &[u8], + _kind: error::ErrorKind, + e: DataElementDeserializeError, + ) -> Self { + e + } +} + +impl error::ParseError<&[u8]> for DataElementDeserializeError { + /// Creates an error from the input position and an [error::ErrorKind] + fn from_error_kind(_input: &[u8], _kind: error::ErrorKind) -> Self { + Self::InvalidStructure + } + + /// Combines an existing error with a new one created from the input + /// position and an [error::ErrorKind]. This is useful when backtracking + /// through a parse tree, accumulating error context on the way + fn append(_input: &[u8], _kind: error::ErrorKind, _other: Self) -> Self { + Self::InvalidStructure + } +} + +/// Serialization of a DE for a particular flavor. +/// +/// The flavor is a type parameter on the trait, rather than on the method, +/// so that a DE can indicate its flavor support by implementing this trait +/// only with the relevant flavors. Deserialization, on the other hand, can +/// express "flavor not supported" for invalid input. +pub trait SerializeDataElement<F: PacketFlavor>: Sealed { + /// Returns the DE type code this DE uses in the header. + fn de_type_code(&self) -> DeTypeCode; + + /// Convert the actual DE content length to the encoded length included in the header. + /// + /// This has a `&self` receiver only so that it can be object-safe; it + /// should not be relevant in the calculation. + /// + /// # Panics + /// + /// Panics if the actual length is invalid for this DE type, or if the + /// encoded length cannot fit in [DeEncodedLength], either of which means + /// that the serialization impl is broken. + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength; + + /// Serialize the data element's data (not including the header) into the sink. + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError>; +} + +/// Errors possible when serializing a DE +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum DataElementSerializeError { + /// Not enough available space + InsufficientSpace, +} + +/// Buffer to serialize a DE, including the header, into. +pub struct DataElementSerializationBuffer { + vec: CapacityLimitedVec<u8, NP_MAX_ADV_CONTENT_LEN>, +} + +impl DataElementSerializationBuffer { + /// Returns `None` if `capacity` exceeds [NP_MAX_ADV_CONTENT_LEN]. + pub(crate) fn new(capacity: usize) -> Option<Self> { + CapacityLimitedVec::new(capacity).map(|vec| Self { vec }) + } + + pub(crate) fn len(&self) -> usize { + self.vec.len() + } + + pub(crate) fn into_inner(self) -> CapacityLimitedVec<u8, NP_MAX_ADV_CONTENT_LEN> { + self.vec + } +} + +impl Sink<u8> for DataElementSerializationBuffer { + fn try_extend_from_slice(&mut self, items: &[u8]) -> Option<()> { + Sink::try_extend_from_slice(&mut self.vec, items) + } + + fn try_push(&mut self, item: u8) -> Option<()> { + Sink::try_push(&mut self.vec, item) + } +} + +/// Trait object reference to a `ToDataElementBundle<I>` with lifetime `'a`. +/// Implements [SerializeDataElement] by deferring to the wrapped trait object. +pub struct DynamicSerializeDataElement<'a, I: PacketFlavor> { + wrapped: &'a dyn SerializeDataElement<I>, +} + +impl<'a, I: PacketFlavor> From<&'a dyn SerializeDataElement<I>> + for DynamicSerializeDataElement<'a, I> +{ + fn from(wrapped: &'a dyn SerializeDataElement<I>) -> Self { + DynamicSerializeDataElement { wrapped } + } +} + +impl<'a, F: PacketFlavor> Sealed for DynamicSerializeDataElement<'a, F> {} + +impl<'a, F: PacketFlavor> SerializeDataElement<F> for DynamicSerializeDataElement<'a, F> { + fn de_type_code(&self) -> DeTypeCode { + self.wrapped.de_type_code() + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + self.wrapped.map_actual_len_to_encoded_len(actual_len) + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + self.wrapped.serialize_contents(sink) + } +} + +/// Maps encoded to actual lengths and vice versa. +/// +/// Each v0 DE type has their own length mapping rules. +pub(in crate::legacy) trait LengthMapper { + /// Convert the encoded DE content length in the header to the actual length to consume from + /// the advertisement, or an error if the encoded length is invalid for the DE type. + fn map_encoded_len_to_actual_len( + encoded_len: DeEncodedLength, + ) -> Result<DeActualLength, DeLengthOutOfRange>; + + /// Convert the actual DE content length to the encoded length included in the header. + /// + /// # Panics + /// + /// Panics if the actual length is invalid for this DE type, or if the + /// encoded length cannot fit in [DeEncodedLength], either of which means + /// that the serialization impl is broken. + fn map_actual_len_to_encoded_len(actual_len: DeActualLength) -> DeEncodedLength; +} + +/// A length predicate used with [DirectMapper]. +pub(in crate::legacy) trait DirectMapPredicate { + /// Return `true` iff the len is valid as a DE encoded len _and_ actual len. + fn is_valid(len: usize) -> bool; +} + +/// A [LengthMapper] that maps the input number directly to the output number without any scaling or +/// shifting. +/// +/// Iff `predicate` evaluates to true, the input number will be transformed into the output type, +/// for both directions. +pub(in crate::legacy) struct DirectMapper<P: DirectMapPredicate> { + _marker: marker::PhantomData<P>, +} + +impl<P: DirectMapPredicate> LengthMapper for DirectMapper<P> { + fn map_encoded_len_to_actual_len( + encoded_len: DeEncodedLength, + ) -> Result<DeActualLength, DeLengthOutOfRange> { + let enc = encoded_len.as_usize(); + if P::is_valid(enc) { + DeActualLength::try_from(enc) + } else { + Err(DeLengthOutOfRange) + } + } + + fn map_actual_len_to_encoded_len(actual_len: DeActualLength) -> DeEncodedLength { + assert!( + P::is_valid(actual_len.as_usize()), + "Broken DE implementation produced invalid length" + ); + DeEncodedLength::try_from(actual_len.as_u8()) + .expect("Actual length has already been validated") + } +}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/tests.rs b/nearby/presence/np_adv/src/legacy/data_elements/tests.rs new file mode 100644 index 0000000..d3f3061 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/tests.rs
@@ -0,0 +1,304 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +use alloc::boxed::Box; + +use crate::header::VERSION_HEADER_V0_UNENCRYPTED; +use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement}; +use crate::legacy::serialize::{encode_de_header, AdvBuilder, UnencryptedEncoder}; +use crate::legacy::Plaintext; + +use super::*; + +#[test] +fn dynamic_de_works() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + let actions: Box<dyn SerializeDataElement<Plaintext>> = + Box::new(ActionsDataElement::<Plaintext>::from(ActionBits::default())); + builder.add_data_element(DynamicSerializeDataElement::from(actions.as_ref())).unwrap(); + + assert_eq!( + &[ + VERSION_HEADER_V0_UNENCRYPTED, + encode_de_header( + ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + DeEncodedLength::from(1), + ), + 0 + ], + builder.into_advertisement().unwrap().as_slice() + ); +} + +pub(in crate::legacy) mod macros { + use alloc::vec::Vec; + + use crate::legacy::data_elements::de_type::DataElementType; + use crate::legacy::deserialize::{DeIterator, DeserializedDataElement}; + use crate::legacy::serialize::SerializedDataElement; + use crate::legacy::PacketFlavor; + + /// Test method body that creates an array, deserializes it into a DE, serializes it, + /// and asserts that the same bytes are produced. + /// + /// Evaluates to (the deserialized DE, the serialized form of the DE). + macro_rules! de_roundtrip_test { + ($de_type:ty, $type_variant:ident, $de_variant:ident, $flavor:ty, $bytes:expr) => {{ + let parsed_de_enum = + crate::legacy::data_elements::tests::macros::construct_and_parse_de::< + $flavor, + >(crate::legacy::data_elements::de_type::DataElementType::$type_variant, &$bytes); + if let crate::legacy::deserialize::DeserializedDataElement::$de_variant(de) = + parsed_de_enum + { + // skip DE header byte + let expected = <$de_type as crate::legacy::data_elements::DeserializeDataElement> + ::deserialize::<$flavor>(&$bytes.as_slice()[1..]).unwrap(); + assert_eq!(expected, de); + + let serialized = crate::legacy::serialize::tests::serialize::<$flavor, _>(&de); + assert_eq!($bytes.as_slice(), serialized.as_slice()); + + (de, serialized) + } else { + panic!("Unexpected variant: {:?}", parsed_de_enum); + } + }}; + } + + pub(in crate::legacy) use de_roundtrip_test; + + /// Construct the serialized DE and parse it + pub(in crate::legacy) fn construct_and_parse_de<F>( + de_type: DataElementType, + contents: &SerializedDataElement, + ) -> DeserializedDataElement<F> + where + F: PacketFlavor, + { + let mut plain_des = + DeIterator::new(contents.as_slice()).collect::<Result<Vec<_>, _>>().unwrap(); + assert_eq!(1, plain_des.len()); + let de = plain_des.swap_remove(0); + assert_eq!( + de_type, + match de { + DeserializedDataElement::Actions(_) => DataElementType::Actions, + DeserializedDataElement::TxPower(_) => DataElementType::TxPower, + } + ); + de + } +} + +mod coverage_gaming { + use alloc::format; + + use nom::error; + use nom::error::ParseError; + + use crate::legacy::data_elements::de_type::DeTypeCode; + use crate::legacy::data_elements::{DataElementDeserializeError, DataElementSerializeError}; + + #[test] + fn data_element_serialize_error_debug_eq_clone() { + let _ = format!("{:?}", DataElementSerializeError::InsufficientSpace.clone()); + assert_eq!( + DataElementSerializeError::InsufficientSpace, + DataElementSerializeError::InsufficientSpace + ); + } + + #[test] + fn data_element_deserialize_error_debug_clone() { + let _ = format!("{:?}", DataElementDeserializeError::InvalidStructure.clone()); + } + + #[test] + fn data_element_deserialize_error_append() { + assert_eq!( + DataElementDeserializeError::InvalidStructure, + DataElementDeserializeError::append( + &[0_u8], + error::ErrorKind::CrLf, + DataElementDeserializeError::InvalidDeType { + de_type: DeTypeCode::try_from(10).unwrap() + }, + ) + ); + } +} + +pub(in crate::legacy) mod test_des { + use alloc::vec; + + use rand::distributions; + use strum_macros::EnumIter; + + use crate::legacy::data_elements::de_type::{ + DeActualLength, DeEncodedLength, DeTypeCode, MAX_DE_ENCODED_LEN, + }; + use crate::legacy::data_elements::{ + DataElementDeserializeError, DataElementSerializationBuffer, DataElementSerializeError, + DeserializeDataElement, LengthMapper, SerializeDataElement, + }; + use crate::legacy::deserialize::{DataElementDeserializer, LengthError, RawDataElement}; + use crate::legacy::serialize::tests::helpers::{LongDataElement, ShortDataElement}; + use crate::legacy::{PacketFlavor, NP_MAX_DE_CONTENT_LEN}; + use crate::private::Sealed; + + /// A [DataElementDeserializer] that can deserialize the test stubs [ShortDataElement] and + /// [LongDataElement]. + pub(in crate::legacy) struct TestDeDeserializer; + + impl DataElementDeserializer for TestDeDeserializer { + type DeTypeDisambiguator = TestDataElementType; + type Deserialized<F: PacketFlavor> = TestDataElement; + + fn map_encoded_len_to_actual_len( + de_type: DeTypeCode, + encoded_len: DeEncodedLength, + ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError> { + match de_type { + ShortDataElement::DE_TYPE_CODE => { + <ShortDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) + .map(|l| (TestDataElementType::Short, l)) + .map_err(|e| e.into()) + } + LongDataElement::DE_TYPE_CODE => { + <LongDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) + .map(|l| (TestDataElementType::Long, l)) + .map_err(|e| e.into()) + } + _ => Err(LengthError::InvalidType), + } + } + + fn deserialize_de<F: PacketFlavor>( + raw_de: RawDataElement<Self>, + ) -> Result<Self::Deserialized<F>, DataElementDeserializeError> { + match raw_de.de_type { + TestDataElementType::Short => { + ShortDataElement::deserialize::<F>(raw_de.contents).map(TestDataElement::Short) + } + TestDataElementType::Long => { + LongDataElement::deserialize::<F>(raw_de.contents).map(TestDataElement::Long) + } + } + } + } + + #[derive(EnumIter, Debug, Clone, Copy)] + pub(in crate::legacy) enum TestDataElementType { + Short, + Long, + } + + #[derive(Debug, PartialEq, Eq, Clone)] + pub(in crate::legacy) enum TestDataElement { + Short(ShortDataElement), + Long(LongDataElement), + } + + impl From<ShortDataElement> for TestDataElement { + fn from(value: ShortDataElement) -> Self { + Self::Short(value) + } + } + + impl From<LongDataElement> for TestDataElement { + fn from(value: LongDataElement) -> Self { + Self::Long(value) + } + } + + impl Sealed for TestDataElement {} + + // Not representative of how the main [DeserializedDataElement] would be used, but handy + // in tests to be able to directly serialize the deserialized representation + impl<F: PacketFlavor> SerializeDataElement<F> for TestDataElement { + fn de_type_code(&self) -> DeTypeCode { + match self { + TestDataElement::Short(s) => { + <ShortDataElement as SerializeDataElement<F>>::de_type_code(s) + } + TestDataElement::Long(l) => { + <LongDataElement as SerializeDataElement<F>>::de_type_code(l) + } + } + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + match self { + TestDataElement::Short(s) => { + <ShortDataElement as SerializeDataElement<F>>::map_actual_len_to_encoded_len( + s, actual_len, + ) + } + TestDataElement::Long(l) => { + <LongDataElement as SerializeDataElement<F>>::map_actual_len_to_encoded_len( + l, actual_len, + ) + } + } + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + match self { + TestDataElement::Short(s) => { + <ShortDataElement as SerializeDataElement<F>>::serialize_contents(s, sink) + } + TestDataElement::Long(l) => { + <LongDataElement as SerializeDataElement<F>>::serialize_contents(l, sink) + } + } + } + } + + impl distributions::Distribution<ShortDataElement> for distributions::Standard { + fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ShortDataElement { + let len = rng.gen_range(0_usize..MAX_DE_ENCODED_LEN.into()); + let mut data = vec![0; len]; + rng.fill(&mut data[..]); + ShortDataElement::new(data) + } + } + + impl distributions::Distribution<LongDataElement> for distributions::Standard { + fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> LongDataElement { + let len = rng.gen_range(LongDataElement::OFFSET..NP_MAX_DE_CONTENT_LEN); + let mut data = vec![0; len]; + rng.fill(&mut data[..]); + LongDataElement::new(data) + } + } + + /// Generate a random instance of the requested de type, or `None` if that type does not support + /// plaintext. + pub(crate) fn random_test_de<R>(de_type: TestDataElementType, rng: &mut R) -> TestDataElement + where + R: rand::Rng, + { + match de_type { + TestDataElementType::Short => TestDataElement::Short(rng.gen()), + TestDataElementType::Long => TestDataElement::Long(rng.gen()), + } + } +}
diff --git a/nearby/presence/np_adv/src/legacy/data_elements/tx_power.rs b/nearby/presence/np_adv/src/legacy/data_elements/tx_power.rs new file mode 100644 index 0000000..e8c787e --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/data_elements/tx_power.rs
@@ -0,0 +1,189 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Data element for TX Power. + +use crate::legacy::data_elements::de_type::{DeActualLength, DeEncodedLength, DeTypeCode}; +use crate::legacy::data_elements::{ + DataElementDeserializeError, DataElementSerializationBuffer, DataElementSerializeError, + DeserializeDataElement, DirectMapPredicate, DirectMapper, LengthMapper, SerializeDataElement, +}; +use crate::legacy::PacketFlavor; +use crate::private::Sealed; +use crate::shared_data::TxPower; +use sink::Sink; + +/// Data element holding a [TxPower]. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TxPowerDataElement { + /// The tx power value + pub tx_power: TxPower, +} + +impl TxPowerDataElement { + /// Gets the underlying Tx Power value + pub fn tx_power_value(&self) -> i8 { + self.tx_power.as_i8() + } +} + +impl From<TxPower> for TxPowerDataElement { + fn from(tx_power: TxPower) -> Self { + Self { tx_power } + } +} + +impl Sealed for TxPowerDataElement {} + +impl<F: PacketFlavor> SerializeDataElement<F> for TxPowerDataElement { + fn de_type_code(&self) -> DeTypeCode { + TxPowerDataElement::DE_TYPE_CODE + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + <Self as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual_len) + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + sink.try_extend_from_slice(self.tx_power.as_i8().to_be_bytes().as_slice()) + .ok_or(DataElementSerializeError::InsufficientSpace) + } +} + +impl DeserializeDataElement for TxPowerDataElement { + const DE_TYPE_CODE: DeTypeCode = match DeTypeCode::try_from(0b0101) { + Ok(t) => t, + Err(_) => unreachable!(), + }; + + type LengthMapper = DirectMapper<TxPowerLengthPredicate>; + + fn deserialize<F: PacketFlavor>( + de_contents: &[u8], + ) -> Result<Self, DataElementDeserializeError> { + de_contents + .try_into() + .ok() + .and_then(|arr: [u8; 1]| TxPower::try_from(i8::from_be_bytes(arr)).ok()) + .map(|tx_power| Self { tx_power }) + .ok_or(DataElementDeserializeError::DeserializeError { de_type: Self::DE_TYPE_CODE }) + } +} + +pub(in crate::legacy) struct TxPowerLengthPredicate; + +impl DirectMapPredicate for TxPowerLengthPredicate { + fn is_valid(len: usize) -> bool { + len == 1 + } +} + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + use crate::legacy::data_elements::de_type::{DeActualLength, DeEncodedLength}; + use crate::legacy::data_elements::tests::macros::de_roundtrip_test; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::data_elements::{DeserializeDataElement, LengthMapper}; + use crate::legacy::serialize::tests::serialize; + use crate::legacy::{Ciphertext, Plaintext}; + use crate::{shared_data, DeLengthOutOfRange}; + use std::panic; + + extern crate std; + + #[test] + fn actual_length_must_be_1() { + for l in [0, 2] { + let actual = DeActualLength::try_from(l).unwrap(); + let _ = panic::catch_unwind(|| { + <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual) + }) + .unwrap_err(); + } + + assert_eq!( + 1, + <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len( + DeActualLength::try_from(1).unwrap(), + ) + .as_u8() + ) + } + + #[test] + fn encoded_length_must_be_1() { + for l in [0, 2] { + assert_eq!( + DeLengthOutOfRange, + <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len( + DeEncodedLength::try_from(l).unwrap() + ) + .unwrap_err() + ) + } + + assert_eq!( + 1, + <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len( + DeEncodedLength::from(1) + ) + .unwrap() + .as_u8() + ); + } + + #[test] + fn tx_power_de_contents_roundtrip_unencrypted() { + let tx = shared_data::TxPower::try_from(-10).unwrap(); + let _ = de_roundtrip_test!( + TxPowerDataElement, + TxPower, + TxPower, + Plaintext, + serialize::<Plaintext, _>(&TxPowerDataElement::from(tx)) + ); + } + + #[test] + fn tx_power_de_contents_roundtrip_ldt() { + let tx = shared_data::TxPower::try_from(-10).unwrap(); + + let _ = de_roundtrip_test!( + TxPowerDataElement, + TxPower, + TxPower, + Ciphertext, + serialize::<Ciphertext, _>(&TxPowerDataElement::from(tx)) + ); + } + + mod coverage_gaming { + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::shared_data::TxPower; + use alloc::format; + + #[test] + fn tx_power_de() { + let de = TxPowerDataElement::from(TxPower::try_from(3).unwrap()); + // debug + let _ = format!("{:?}", de); + // trivial accessor + assert_eq!(3, de.tx_power_value()); + } + } +}
diff --git a/nearby/presence/np_adv/src/legacy/de_type/mod.rs b/nearby/presence/np_adv/src/legacy/de_type/mod.rs deleted file mode 100644 index 304347d..0000000 --- a/nearby/presence/np_adv/src/legacy/de_type/mod.rs +++ /dev/null
@@ -1,356 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! V0 data element types. -//! -//! In V0, there are only 16 DE types total, and parsing unknown types is not possible, so we can -//! represent all known DE types in enums without needing to handle the "unknown type" case. - -use crate::{ - de_type::IdentityDataElementType, - legacy::{ - actions::ActionsDataElement, - data_elements::{DataElement as _, TxPowerDataElement}, - Ciphertext, PacketFlavorEnum, Plaintext, NP_MAX_DE_CONTENT_LEN, - }, - DeLengthOutOfRange, -}; -use core::ops; -use ldt_np_adv::NP_LEGACY_METADATA_KEY_LEN; -use strum_macros::EnumIter; - -#[cfg(test)] -mod tests; - -/// A V0 DE type in `[0, 15]`. -#[derive(Debug, PartialEq, Eq, Hash)] -pub(crate) struct DeTypeCode { - /// The code used in a V0 adv header - code: u8, -} - -impl DeTypeCode { - /// Returns a u8 in `[0, 15`]. - pub(crate) fn as_u8(&self) -> u8 { - self.code - } -} - -/// The DE type code is out of range for v0 DE types. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(crate) struct DeTypeCodeOutOfRange; - -impl TryFrom<u8> for DeTypeCode { - type Error = DeTypeCodeOutOfRange; - - fn try_from(value: u8) -> Result<Self, Self::Error> { - if value < 16 { - Ok(Self { code: value }) - } else { - Err(DeTypeCodeOutOfRange) - } - } -} - -/// The actual length of a DE, not the encoded representation. -/// -/// See [DeEncodedLength] for the encoded length. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DeActualLength { - /// Invariant: <= `NP_MAX_DE_CONTENT_LEN`. - len: u8, -} - -impl DeActualLength { - pub(crate) const ZERO: DeActualLength = DeActualLength { len: 0 }; - - pub(crate) fn as_usize(&self) -> usize { - self.len as usize - } -} - -impl TryFrom<u8> for DeActualLength { - type Error = DeLengthOutOfRange; - - fn try_from(value: u8) -> Result<Self, Self::Error> { - if (value as usize) <= NP_MAX_DE_CONTENT_LEN { - Ok(Self { len: value }) - } else { - Err(DeLengthOutOfRange) - } - } -} - -impl TryFrom<usize> for DeActualLength { - type Error = DeLengthOutOfRange; - - fn try_from(value: usize) -> Result<Self, Self::Error> { - if value <= NP_MAX_DE_CONTENT_LEN { - Ok(Self { len: value as u8 }) - } else { - Err(DeLengthOutOfRange) - } - } -} - -/// The encoded length of a DE, not the actual length of the DE contents. -/// -/// See [DeActualLength] for the length of the contents. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct DeEncodedLength { - /// Invariant: `len <= 0x0F` (15, aka 4 bits) - len: u8, -} - -impl DeEncodedLength { - /// Returns a u8 in `[0, 15]` - pub(crate) fn as_u8(&self) -> u8 { - self.len - } - - /// Returns a usize in `[0, 15]` - pub(crate) fn as_usize(&self) -> usize { - self.len as usize - } -} - -impl TryFrom<u8> for DeEncodedLength { - type Error = DeLengthOutOfRange; - - fn try_from(value: u8) -> Result<Self, Self::Error> { - if value < 16 { - Ok(Self { len: value }) - } else { - Err(DeLengthOutOfRange) - } - } -} - -/// DE types for normal DEs (not an identity). -/// -/// May be contained in identity DEs (see [IdentityDataElementType]). Must not overlap with -/// [IdentityDataElementType]. -#[derive(EnumIter, Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum PlainDataElementType { - TxPower, - Actions, -} - -impl PlainDataElementType { - pub(crate) fn as_generic_de_type(&self) -> DataElementType { - match self { - PlainDataElementType::TxPower => DataElementType::TxPower, - PlainDataElementType::Actions => DataElementType::Actions, - } - } - - pub(crate) fn supports_flavor(&self, flavor: PacketFlavorEnum) -> bool { - match self { - PlainDataElementType::Actions => { - // Actions is effectively two different DEs based on which actions it can - // contain, so we have to check them separately. The Plaintext one obviously - // supports plaintext, and vice versa, so we could just say `true` here, but we - // spell it out to be consistent with the other DE types. - match flavor { - PacketFlavorEnum::Plaintext => { - ActionsDataElement::<Plaintext>::supports_flavor(flavor) - } - PacketFlavorEnum::Ciphertext => { - ActionsDataElement::<Ciphertext>::supports_flavor(flavor) - } - } - } - PlainDataElementType::TxPower => TxPowerDataElement::supports_flavor(flavor), - } - } -} - -/// Corresponds to the different implementations of [DataElement]. -/// -/// It's intended for use cases that don't care if a DE is a plain or identity DE. Every variant -/// corresponds to either a [PlainDataElementType] or a [IdentityDataElementType]. -#[derive(EnumIter, Debug, Clone, Copy, PartialEq, Eq)] -#[allow(missing_docs)] -#[doc(hidden)] -pub enum DataElementType { - PrivateIdentity, - TrustedIdentity, - PublicIdentity, - ProvisionedIdentity, - TxPower, - Actions, -} - -const DE_TYPES_BY_CODE: [Option<DataElementType>; 16] = [ - None, // 0b0000 - Some(DataElementType::PrivateIdentity), // 0b0001 - Some(DataElementType::TrustedIdentity), // 0b0010 - Some(DataElementType::PublicIdentity), // 0b0011 - Some(DataElementType::ProvisionedIdentity), // 0b0100 - Some(DataElementType::TxPower), // 0b0101 - Some(DataElementType::Actions), // 0b0110 - None, // 0b0111 - None, // 0b1000 - None, // 0b1001 - None, // 0b1010 - None, // 0b1011 - None, // 0b1100 - None, // 0b1101 - None, // 0b1110 - None, // 0b1111 -]; - -impl DataElementType { - /// Salt + key + at least 2 bytes of DE to make LDT ciphertext min length - const VALID_ENCRYPTED_IDENTITY_DE_ACTUAL_LEN: ops::RangeInclusive<usize> = - (2 + NP_LEGACY_METADATA_KEY_LEN + 2..=NP_MAX_DE_CONTENT_LEN); - const VALID_ENCRYPTED_IDENTITY_DE_HEADER_LEN: ops::RangeInclusive<usize> = (2..=6); - - /// If there is a corresponding [ContainerDataElementType], returns it, otherwise None. - pub(crate) fn try_as_identity_de_type(&self) -> Option<IdentityDataElementType> { - match self { - DataElementType::PrivateIdentity => Some(IdentityDataElementType::Private), - DataElementType::TrustedIdentity => Some(IdentityDataElementType::Trusted), - DataElementType::PublicIdentity => Some(IdentityDataElementType::Public), - DataElementType::ProvisionedIdentity => Some(IdentityDataElementType::Provisioned), - DataElementType::TxPower | DataElementType::Actions => None, - } - } - - /// If there is a corresponding [PlainDataElementType], returns it, otherwise None. - pub(crate) fn try_as_plain_de_type(&self) -> Option<PlainDataElementType> { - match self { - DataElementType::TxPower => Some(PlainDataElementType::TxPower), - DataElementType::Actions => Some(PlainDataElementType::Actions), - DataElementType::PrivateIdentity - | DataElementType::TrustedIdentity - | DataElementType::PublicIdentity - | DataElementType::ProvisionedIdentity => None, - } - } - - /// Returns the matching type for the code, else `None` - pub(crate) fn from_type_code(de_type: DeTypeCode) -> Option<Self> { - DE_TYPES_BY_CODE.get(de_type.as_u8() as usize).and_then(|o| *o) - } - - /// A type code in `[0,15]` for use in the high bits of the DE header byte. - pub(crate) fn type_code(&self) -> DeTypeCode { - match self { - DataElementType::PrivateIdentity => IdentityDataElementType::Private.shared_type_code(), - DataElementType::TrustedIdentity => IdentityDataElementType::Trusted.shared_type_code(), - DataElementType::PublicIdentity => IdentityDataElementType::Public.shared_type_code(), - DataElementType::ProvisionedIdentity => { - IdentityDataElementType::Provisioned.shared_type_code() - } - DataElementType::TxPower => 0b0101, - DataElementType::Actions => 0b0110, - } - .try_into() - .expect("hardcoded type codes are valid") - } - - /// Convert the actual DE length to the encoded length included in the header. - /// - /// Returns `Err` if the actual length is invalid for the type, or the corresponding encoded length is out of range. - pub(crate) fn encoded_len_for_actual_len( - &self, - actual_len: DeActualLength, - ) -> Result<DeEncodedLength, DeLengthOutOfRange> { - match self { - // TODO 0-length provisioned - DataElementType::PrivateIdentity - | DataElementType::TrustedIdentity - | DataElementType::ProvisionedIdentity => { - if !Self::VALID_ENCRYPTED_IDENTITY_DE_ACTUAL_LEN.contains(&actual_len.as_usize()) { - Err(DeLengthOutOfRange) - } else { - actual_len - .len - .checked_sub(16) - .ok_or(DeLengthOutOfRange) - .and_then(|n| n.try_into()) - } - } - DataElementType::PublicIdentity => { - if actual_len.len != 0 { - Err(DeLengthOutOfRange) - } else { - actual_len.len.try_into() - } - } - DataElementType::TxPower => { - if actual_len.len != 1 { - Err(DeLengthOutOfRange) - } else { - actual_len.len.try_into() - } - } - DataElementType::Actions => { - // doesn't matter which variant is used - if !ActionsDataElement::<Plaintext>::ACTIONS_LEN.contains(&actual_len.as_usize()) { - Err(DeLengthOutOfRange) - } else { - actual_len.len.try_into() - } - } - } - } - - /// Convert the length in the header to the actual DE length. - /// - /// Returns `Err` if the encoded length is invalid for the type, or the corresponding actual length is out of range. - pub(crate) fn actual_len_for_encoded_len( - &self, - header_len: DeEncodedLength, - ) -> Result<DeActualLength, DeLengthOutOfRange> { - match self { - DataElementType::PrivateIdentity - | DataElementType::TrustedIdentity - // TODO provisioned 0 length - | DataElementType::ProvisionedIdentity => { - if !Self::VALID_ENCRYPTED_IDENTITY_DE_HEADER_LEN.contains(&header_len.as_usize()) { - Err(DeLengthOutOfRange) - } else { - header_len - .len - .checked_add(16) - .ok_or(DeLengthOutOfRange) - .and_then(|n| n.try_into()) - } - } - DataElementType::PublicIdentity => { - if header_len.len != 0 { - Err(DeLengthOutOfRange) - } else { - header_len.len.try_into() - } - } - DataElementType::TxPower => { - if header_len.len != 1 { - Err(DeLengthOutOfRange) - } else { - header_len.len.try_into() - } - } - DataElementType::Actions => { - if !ActionsDataElement::<Plaintext>::ACTIONS_LEN.contains(&header_len.as_usize()) { - Err(DeLengthOutOfRange) - } else { - header_len.len.try_into() - } - } - } - } -}
diff --git a/nearby/presence/np_adv/src/legacy/de_type/tests.rs b/nearby/presence/np_adv/src/legacy/de_type/tests.rs deleted file mode 100644 index fc64321..0000000 --- a/nearby/presence/np_adv/src/legacy/de_type/tests.rs +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use super::*; -use crate::legacy::serialize::id_de_type_as_generic_de_type; -use std::{collections, vec::Vec}; -use strum::IntoEnumIterator as _; - -#[test] -fn no_plain_vs_identity_type_overlap() { - let plain_types = - PlainDataElementType::iter().map(|t| t.as_generic_de_type()).collect::<Vec<_>>(); - let identity_types = - IdentityDataElementType::iter().map(id_de_type_as_generic_de_type).collect::<Vec<_>>(); - - for plain_de_type in plain_types.iter() { - assert!(!identity_types.iter().any(|i| i == plain_de_type)); - assert_eq!(None, plain_de_type.try_as_identity_de_type()); - } - - for id_de_type in identity_types.iter() { - assert!(!plain_types.iter().any(|p| p == id_de_type)); - assert_eq!(None, id_de_type.try_as_plain_de_type()); - } -} - -#[test] -fn generic_type_is_either_plain_or_identity() { - let generic_types = DataElementType::iter().collect::<Vec<_>>(); - - for g in generic_types.iter() { - let total = g.try_as_identity_de_type().map(|_| 1).unwrap_or(0) - + g.try_as_plain_de_type().map(|_| 1).unwrap_or(0); - - assert_eq!(1, total); - } -} - -#[test] -fn generic_de_type_codes_are_consistent() { - for det in DataElementType::iter() { - let actual = DataElementType::from_type_code(det.type_code()); - assert_eq!(Some(det), actual) - } -} - -#[test] -fn generic_de_distinct_type_codes() { - let codes = - DataElementType::iter().map(|det| det.type_code()).collect::<collections::HashSet<_>>(); - assert_eq!(codes.len(), DataElementType::iter().count()); -} - -#[test] -fn generic_de_no_accidentally_mapped_type_codes() { - let codes = - DataElementType::iter().map(|det| det.type_code()).collect::<collections::HashSet<_>>(); - for possible_code in 0..=15 { - if codes.contains(&possible_code.try_into().unwrap()) { - continue; - } - - assert_eq!(None, DataElementType::from_type_code(possible_code.try_into().unwrap())); - } -} - -#[test] -fn actions_de_length_zero_rejected() { - let encoded = DeEncodedLength::try_from(0).unwrap(); - let maybe_actual_len = DataElementType::Actions.actual_len_for_encoded_len(encoded); - assert_eq!(Err(DeLengthOutOfRange), maybe_actual_len); -} - -#[test] -fn de_length_actual_encoded_round_trip() { - for de_type in DataElementType::iter() { - // for all possible lengths, calculate actual -> encoded and the inverse - let actual_to_encoded = (0_u8..=255) - .filter_map(|num| num.try_into().ok()) - .filter_map(|actual: DeActualLength| { - de_type.encoded_len_for_actual_len(actual).ok().map(|encoded| (actual, encoded)) - }) - .collect::<collections::HashMap<_, _>>(); - - let encoded_to_actual = (0_u8..=255) - .filter_map(|num| num.try_into().ok()) - .filter_map(|encoded: DeEncodedLength| { - de_type.actual_len_for_encoded_len(encoded).ok().map(|actual| (encoded, actual)) - }) - .collect::<collections::HashMap<_, _>>(); - - // ensure the two maps are inverses of each other - assert_eq!( - actual_to_encoded, - encoded_to_actual.into_iter().map(|(encoded, actual)| (actual, encoded)).collect(), - "de type: {de_type:?}" - ); - } -}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/intermediate/mod.rs b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/mod.rs new file mode 100644 index 0000000..13ede05 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/mod.rs
@@ -0,0 +1,146 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The first stage of deserialization: just header data (if any) and the bulk contents of the +//! advertisement, with no disaggregation into individual data elements. + +use crate::header::V0Encoding; +use crate::helpers::parse_byte_array; +use crate::legacy::deserialize::{ + AdvDeserializeError, DeIterator, DecryptError, DecryptedAdvContents, +}; +#[cfg(test)] +use crate::legacy::deserialize::{DataElementDeserializer, GenericDeIterator}; +use crate::legacy::{Plaintext, NP_MIN_ADV_CONTENT_LEN}; +use crypto_provider::CryptoProvider; +use ldt_np_adv::V0Salt; +use nom::combinator; + +#[cfg(test)] +mod tests; + +/// The header components, if any, and the bytes that will later be decrypted and/or parsed into DEs. +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum IntermediateAdvContents<'d> { + /// Plaintext advertisements + Unencrypted(UnencryptedAdvContents<'d>), + /// Ciphertext advertisements + Ldt(LdtAdvContents<'d>), +} + +impl<'d> IntermediateAdvContents<'d> { + #[cfg(test)] + pub(crate) fn as_unencrypted(&self) -> Option<&UnencryptedAdvContents<'d>> { + match self { + IntermediateAdvContents::Unencrypted(c) => Some(c), + IntermediateAdvContents::Ldt(_) => None, + } + } + + #[cfg(test)] + pub(crate) fn as_ldt(&self) -> Option<&LdtAdvContents<'d>> { + match self { + IntermediateAdvContents::Unencrypted(_) => None, + IntermediateAdvContents::Ldt(c) => Some(c), + } + } + + /// Performs basic structural checks on header and content, but doesn't deserialize DEs or + /// decrypt. + pub(crate) fn deserialize<C: CryptoProvider>( + encoding: V0Encoding, + input: &[u8], + ) -> Result<IntermediateAdvContents<'_>, AdvDeserializeError> { + match encoding { + V0Encoding::Unencrypted => { + if input.len() < NP_MIN_ADV_CONTENT_LEN { + return Err(AdvDeserializeError::NoDataElements); + } + Ok(IntermediateAdvContents::Unencrypted(UnencryptedAdvContents { data: input })) + } + V0Encoding::Ldt => { + let (ciphertext, salt) = + parse_v0_salt(input).map_err(|_| AdvDeserializeError::InvalidStructure)?; + LdtAdvContents::new::<C>(salt, ciphertext) + .ok_or(AdvDeserializeError::InvalidStructure) + .map(IntermediateAdvContents::Ldt) + } + } + } +} + +/// The contents of a plaintext advertisement. +#[derive(Debug, PartialEq, Eq)] +pub struct UnencryptedAdvContents<'d> { + /// Contents of the advertisement after the version header. + /// + /// Contents are at least [NP_MIN_ADV_CONTENT_LEN]. + data: &'d [u8], +} + +impl<'d> UnencryptedAdvContents<'d> { + /// Returns an iterator over the v0 data elements + pub fn data_elements(&self) -> DeIterator<'d, Plaintext> { + DeIterator::new(self.data) + } + + #[cfg(test)] + pub(in crate::legacy) fn generic_data_elements<D: DataElementDeserializer>( + &self, + ) -> GenericDeIterator<Plaintext, D> { + GenericDeIterator::new(self.data) + } +} + +/// Contents of an encrypted advertisement before decryption. +#[derive(Debug, PartialEq, Eq)] +pub(crate) struct LdtAdvContents<'d> { + /// Salt from the advertisement, converted into a padder. + /// Pre-calculated so it's only derived once across multiple decrypt attempts. + salt_padder: ldt::XorPadder<{ crypto_provider::aes::BLOCK_SIZE }>, + /// The salt instance used for encryption of this advertisement. + salt: V0Salt, + /// Ciphertext containing the identity token and any data elements. + /// Must be a valid length for LDT. + ciphertext: &'d [u8], +} + +impl<'d> LdtAdvContents<'d> { + /// Returns `None` if `ciphertext` is not a valid LDT-XTS-AES ciphertext length. + pub(crate) fn new<C: CryptoProvider>(salt: V0Salt, ciphertext: &'d [u8]) -> Option<Self> { + if !ldt_np_adv::VALID_INPUT_LEN.contains(&ciphertext.len()) { + return None; + } + Some(Self { salt_padder: ldt_np_adv::salt_padder::<C>(salt), salt, ciphertext }) + } + + /// Try decrypting with an identity's LDT cipher and deserializing the resulting data elements. + /// + /// Returns the decrypted data if decryption and verification succeeded and the resulting DEs could be parsed + /// successfully, otherwise `Err`. + pub(crate) fn try_decrypt<C: CryptoProvider>( + &self, + cipher: &ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C>, + ) -> Result<DecryptedAdvContents, DecryptError> { + let (identity_token, plaintext) = cipher + .decrypt_and_verify(self.ciphertext, &self.salt_padder) + .map_err(|_e| DecryptError::DecryptOrVerifyError)?; + + Ok(DecryptedAdvContents::new(identity_token, self.salt, plaintext)) + } +} + +fn parse_v0_salt(input: &[u8]) -> nom::IResult<&[u8], V0Salt> { + combinator::map(parse_byte_array::<2>, V0Salt::from)(input) +}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/error_conditions.rs b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/error_conditions.rs new file mode 100644 index 0000000..5cbd784 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/error_conditions.rs
@@ -0,0 +1,85 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +mod unencrypted_encoder { + use crate::header::V0Encoding; + use crate::legacy::deserialize::intermediate::IntermediateAdvContents; + use crate::legacy::deserialize::AdvDeserializeError; + use crypto_provider_default::CryptoProviderImpl; + + #[test] + fn parse_zero_len_error() { + assert_eq!( + AdvDeserializeError::NoDataElements, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &[], + ) + .unwrap_err() + ); + } +} + +mod ldt_encoder { + use crate::header::V0Encoding; + use crate::legacy::deserialize::intermediate::IntermediateAdvContents; + use crate::legacy::deserialize::AdvDeserializeError; + use alloc::vec; + use crypto_provider_default::CryptoProviderImpl; + use ldt_np_adv::{V0_IDENTITY_TOKEN_LEN, V0_SALT_LEN}; + + #[test] + fn all_below_min_ldt_len_error() { + for len in 0..(V0_SALT_LEN + ldt_np_adv::VALID_INPUT_LEN.start) { + assert_eq!( + AdvDeserializeError::InvalidStructure, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + &vec![0; len], + ) + .unwrap_err() + ); + } + + // 1 more byte is enough + let data = &[0; ldt_np_adv::VALID_INPUT_LEN.start + V0_SALT_LEN]; + assert!(IntermediateAdvContents::deserialize::<CryptoProviderImpl>(V0Encoding::Ldt, data) + .is_ok()) + } + + #[test] + fn above_max_ldt_len_error() { + let salt = [0x55; V0_SALT_LEN]; + // this is longer than can fit in a BLE 4.2 adv, but we're just testing LDT limits here + let payload_len = 2 + crypto_provider::aes::BLOCK_SIZE; + let data = + &[&salt, [0x11; V0_IDENTITY_TOKEN_LEN].as_slice(), &vec![0xCC; payload_len]].concat(); + // 1 byte long + assert_eq!(V0_SALT_LEN + ldt_np_adv::VALID_INPUT_LEN.end, data.len()); + + assert_eq!( + AdvDeserializeError::InvalidStructure, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>(V0Encoding::Ldt, data) + .unwrap_err() + ); + + // 1 fewer byte is enough + let data = &[&salt, [0x11; V0_IDENTITY_TOKEN_LEN].as_slice(), &vec![0xCC; payload_len - 1]] + .concat(); + assert!(IntermediateAdvContents::deserialize::<CryptoProviderImpl>(V0Encoding::Ldt, data) + .is_ok()) + } +}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/happy_path.rs b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/happy_path.rs new file mode 100644 index 0000000..f74c1a9 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/happy_path.rs
@@ -0,0 +1,106 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +mod unencrypted_encoder { + use crate::header::V0Encoding; + use crate::legacy::data_elements::de_type::{DeEncodedLength, DeTypeCode, MAX_DE_ENCODED_LEN}; + use crate::legacy::deserialize::intermediate::IntermediateAdvContents; + use crate::legacy::serialize::encode_de_header; + use crate::legacy::NP_MAX_DE_CONTENT_LEN; + use crypto_provider_default::CryptoProviderImpl; + + #[test] + fn parse_min_len() { + let header = encode_de_header(DeTypeCode::try_from(14).unwrap(), DeEncodedLength::from(0)); + assert_eq!( + &[header], + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &[header], + ) + .unwrap() + .as_unencrypted() + .unwrap() + .data + ) + } + + #[test] + fn parse_max_len() { + let header = encode_de_header( + DeTypeCode::try_from(15).unwrap(), + DeEncodedLength::try_from(MAX_DE_ENCODED_LEN).unwrap(), + ); + let data = &[&[header], [0x22; NP_MAX_DE_CONTENT_LEN].as_slice()].concat(); + assert_eq!( + data, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + data, + ) + .unwrap() + .as_unencrypted() + .unwrap() + .data + ) + } +} + +mod ldt_encoder { + use crate::header::V0Encoding; + use crate::legacy::deserialize::intermediate::{IntermediateAdvContents, LdtAdvContents}; + use crate::legacy::NP_MAX_ADV_CONTENT_LEN; + use crypto_provider_default::CryptoProviderImpl; + use ldt::LdtCipher; + use ldt_np_adv::{salt_padder, V0_IDENTITY_TOKEN_LEN, V0_SALT_LEN}; + + #[test] + fn parse_min_len() { + // not going to bother to make it look like encrypted DEs since this layer doesn't care + let salt = [0x55; V0_SALT_LEN]; + let data = &[&salt, [0x11; V0_IDENTITY_TOKEN_LEN].as_slice(), &[0xCC; 2]].concat(); + assert_eq!( + V0_SALT_LEN + + ldt_np_adv::NpLdtEncryptCipher::<CryptoProviderImpl>::VALID_INPUT_LEN.start, + data.len() + ); + + assert_ldt_contents(salt, data); + } + + #[test] + fn parse_max_len() { + let salt = [0x55; V0_SALT_LEN]; + let data = &[&salt, [0x11; V0_IDENTITY_TOKEN_LEN].as_slice(), &[0xCC; 7]].concat(); + assert_eq!(NP_MAX_ADV_CONTENT_LEN, data.len()); + + assert_ldt_contents(salt, data); + } + + fn assert_ldt_contents(salt: [u8; V0_SALT_LEN], data: &[u8]) { + assert_eq!( + &LdtAdvContents { + salt_padder: salt_padder::<CryptoProviderImpl>(salt.into()), + salt: salt.into(), + ciphertext: &data[V0_SALT_LEN..], + }, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>(V0Encoding::Ldt, data) + .unwrap() + .as_ldt() + .unwrap() + ); + } +}
diff --git a/nearby/util/pourover_macro_core/src/lib.rs b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/mod.rs similarity index 79% copy from nearby/util/pourover_macro_core/src/lib.rs copy to nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/mod.rs index ae06345..289fdd8 100644 --- a/nearby/util/pourover_macro_core/src/lib.rs +++ b/nearby/presence/np_adv/src/legacy/deserialize/intermediate/tests/mod.rs
@@ -1,10 +1,10 @@ -// Copyright 2024 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod jni_method; -pub use jni_method::jni_method; +mod error_conditions; +mod happy_path;
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/mod.rs b/nearby/presence/np_adv/src/legacy/deserialize/mod.rs index d6c6b36..d305b57 100644 --- a/nearby/presence/np_adv/src/legacy/deserialize/mod.rs +++ b/nearby/presence/np_adv/src/legacy/deserialize/mod.rs
@@ -16,449 +16,320 @@ //! //! This module only deals with the _contents_ of an advertisement, not the advertisement header. +use core::fmt; use core::marker::PhantomData; +use crate::legacy::data_elements::tx_power::TxPowerDataElement; use crate::{ credential::v0::V0, - de_type::EncryptedIdentityDataElementType, legacy::{ - actions, - data_elements::{DataElement, *}, - de_type::{DataElementType, DeEncodedLength, DeTypeCode, PlainDataElementType}, - Ciphertext, PacketFlavor, Plaintext, ShortMetadataKey, NP_MAX_DE_CONTENT_LEN, + data_elements::{ + actions, + de_type::{DeEncodedLength, DeTypeCode}, + DataElementDeserializeError, DeserializeDataElement, LengthMapper, + }, + Ciphertext, PacketFlavor, }, - HasIdentityMatch, PlaintextIdentityMode, + DeLengthOutOfRange, }; use array_view::ArrayView; -use crypto_provider::CryptoProvider; -use ldt_np_adv::{LegacySalt, NP_LEGACY_METADATA_KEY_LEN}; -use nom::{bytes, combinator, number, sequence}; - -use super::BLE_ADV_SVC_CONTENT_LEN; +use ldt_np_adv::{V0IdentityToken, V0Salt, NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN}; +use nom::{bytes, combinator, number, Finish}; #[cfg(test)] mod tests; -/// Deserialize an advertisement into data elements (if plaintext) or an identity type and -/// ciphertext. -pub(crate) fn deserialize_adv_contents<C: CryptoProvider>( - input: &[u8], -) -> Result<IntermediateAdvContents<'_>, AdvDeserializeError> { - parse_raw_adv_contents::<C>(input).and_then(|raw_adv| match raw_adv { - RawAdvertisement::Plaintext(adv_contents) => { - if adv_contents.data_elements().next().is_none() { - return Err(AdvDeserializeError::NoPublicDataElements); - } +pub(crate) mod intermediate; - Ok(IntermediateAdvContents::Plaintext(adv_contents)) - } - RawAdvertisement::Ciphertext(eac) => Ok(IntermediateAdvContents::Ciphertext(eac)), - }) -} - -/// Parse an advertisement's contents to the level of raw data elements (i.e no decryption, -/// no per-type deserialization, etc). -/// -/// Consumes the entire input. -fn parse_raw_adv_contents<C: CryptoProvider>( - input: &[u8], -) -> Result<RawAdvertisement, AdvDeserializeError> { - if input.is_empty() { - return Err(AdvDeserializeError::MissingIdentity); - } - match parse_de(input) { - Ok((rem, identity_de)) => { - if let Some(identity_de_type) = identity_de.de_type.try_as_identity_de_type() { - match identity_de_type.as_encrypted_identity_de_type() { - Some(encrypted_de_type) => { - if matches!(parse_de(rem), Err(nom::Err::Error(..))) { - match encrypted_de_type { - // TODO handle length=0 provisioned identity DEs - EncryptedIdentityDataElementType::Private - | EncryptedIdentityDataElementType::Trusted - | EncryptedIdentityDataElementType::Provisioned => combinator::map( - parse_encrypted_identity_de_contents, - |(salt, payload)| { - RawAdvertisement::Ciphertext(EncryptedAdvContents { - identity_type: encrypted_de_type, - salt_padder: ldt_np_adv::salt_padder::<16, C>(salt), - salt, - ciphertext: payload, - }) - }, - )( - identity_de.contents, - ) - .map(|(_rem, contents)| contents) - .map_err(|_e| AdvDeserializeError::AdvertisementDeserializeError), - } - } else { - Err(AdvDeserializeError::TooManyTopLevelDataElements) - } - } - // It's an identity de, but not encrypted, so it must be public, and the rest - // must be plain - None => Ok(RawAdvertisement::Plaintext(PlaintextAdvContents { - identity_type: PlaintextIdentityMode::Public, - data: rem, - })), - } - } else { - Err(AdvDeserializeError::MissingIdentity) - } - } - Err(nom::Err::Error(_)) | Err(nom::Err::Failure(_)) => { - Err(AdvDeserializeError::AdvertisementDeserializeError) - } - Err(nom::Err::Incomplete(_)) => { - panic!("Should not hit Incomplete when using nom::complete parsers") - } - } -} +use crate::credential::matched::HasIdentityMatch; +use crate::legacy::data_elements::actions::ActionsDataElement; +use crate::legacy::data_elements::de_type::{DataElementType, DeActualLength}; +use crate::legacy::Plaintext; +/// exposed because the unencrypted case isn't just for intermediate: no further processing is needed +pub use intermediate::UnencryptedAdvContents; /// Legacy advertisement parsing errors #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum AdvDeserializeError { - /// Parsing the overall advertisement or DE structure failed - AdvertisementDeserializeError, - /// Must not have any other top level data elements if there is an encrypted identity DE - TooManyTopLevelDataElements, - /// Missing identity DE - MissingIdentity, - /// Non-identity DE contents must not be empty - NoPublicDataElements, -} - -/// Parse an individual DE into its header and contents. -fn parse_de(input: &[u8]) -> nom::IResult<&[u8], RawDataElement, DataElementDeserializeError> { - let (remaining, (de_type, actual_len)) = - combinator::map_opt(number::complete::u8, |de_header| { - // header: LLLLTTTT - let len = de_header >> 4; - let de_type = de_header & 0x0F; - DeTypeCode::try_from(de_type).ok().and_then(DataElementType::from_type_code).and_then( - |de_type| { - len.try_into() - .ok() - .and_then(|len: DeEncodedLength| { - de_type.actual_len_for_encoded_len(len).ok() - }) - .map(|len| (de_type, len)) - }, - ) - })(input)?; - - combinator::map(bytes::complete::take(actual_len.as_usize()), move |contents| RawDataElement { - de_type, - contents, - })(remaining) -} - -/// Parse legacy encrypted identity DEs (private, trusted, provisioned) into salt and ciphertext -/// (encrypted metadata key and at least 2 bytes of DEs). -/// -/// Consumes the entire input. -fn parse_encrypted_identity_de_contents( - de_contents: &[u8], -) -> nom::IResult<&[u8], (ldt_np_adv::LegacySalt, &[u8])> { - combinator::all_consuming(sequence::tuple(( - // 2-byte salt - combinator::map( - combinator::map_res(bytes::complete::take(2_usize), |slice: &[u8]| slice.try_into()), - |arr: [u8; 2]| arr.into(), - ), - // 14-byte encrypted metadata key plus encrypted DEs, which must together be at least 16 - // bytes (AES block size), and at most a full DE minus the size of the salt. - bytes::complete::take_while_m_n(16_usize, NP_MAX_DE_CONTENT_LEN - 2, |_| true), - )))(de_contents) + /// Header or other structure was invalid + InvalidStructure, + /// DE contents must not be empty + NoDataElements, } /// A data element with content length determined and validated per its type's length rules, but /// no further decoding performed. #[derive(Debug, PartialEq, Eq)] -struct RawDataElement<'d> { - de_type: DataElementType, +pub(in crate::legacy) struct RawDataElement<'d, D: DataElementDeserializer> { + pub(in crate::legacy) de_type: D::DeTypeDisambiguator, /// Byte array payload of the data element, without the DE header. - contents: &'d [u8], + pub(in crate::legacy) contents: &'d [u8], } -/// An advertisement broken down into data elements, but before decryption or mapping to higher -/// level DE representations. -#[derive(Debug, PartialEq, Eq)] -enum RawAdvertisement<'d> { - Plaintext(PlaintextAdvContents<'d>), - Ciphertext(EncryptedAdvContents<'d>), +impl<'d, D: DataElementDeserializer> RawDataElement<'d, D> { + /// Parse an individual DE into its header and contents. + fn parse(input: &'d [u8]) -> nom::IResult<&[u8], Self, DataElementDeserializeError> { + let (input, (de_type, actual_len)) = combinator::map_res( + combinator::map_opt(number::complete::u8, |de_header| { + // header: LLLLTTTT + let len = de_header >> 4; + let de_type_num = de_header & 0x0F; + + // these can't fail since both inputs are 4 bits and will fit + DeTypeCode::try_from(de_type_num).ok().and_then(|de_type| { + DeEncodedLength::try_from(len).ok().map(|encoded_len| (de_type, encoded_len)) + }) + }), + |(de_type, encoded_len)| { + D::map_encoded_len_to_actual_len(de_type, encoded_len).map_err(|e| match e { + LengthError::InvalidLength => { + DataElementDeserializeError::InvalidDeLength { de_type, len: encoded_len } + } + LengthError::InvalidType => { + DataElementDeserializeError::InvalidDeType { de_type } + } + }) + }, + )(input)?; + + combinator::map(bytes::complete::take(actual_len.as_usize()), move |contents| { + RawDataElement { de_type, contents } + })(input) + } } /// An iterator that parses the given data elements iteratively. In environments /// where memory is not severely constrained, it is usually safer to collect -/// this into `Result<Vec<PlainDataElement>>` so the validity of the whole +/// this into `Result<Vec<DeserializedDataElement>>` so the validity of the whole /// advertisement can be checked before proceeding with further processing. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct PlainDeIterator<'d, F> -where - F: PacketFlavor, - actions::ActionsDataElement<F>: DataElement, -{ - /// Data to be parsed, containing a sequence of data elements in serialized - /// form. This should not contain the identity data elements. - data: &'d [u8], - _marker: PhantomData<F>, +pub struct DeIterator<'d, F> { + delegate: GenericDeIterator<'d, F, StandardDeserializer>, } -impl<'d, F> PlainDeIterator<'d, F> -where - F: PacketFlavor, - actions::ActionsDataElement<F>: DataElement, -{ - fn raw_de_to_plain_de( - raw_de: RawDataElement<'d>, - ) -> Result<PlainDataElement<F>, DataElementDeserializeError> { - let de_type = raw_de - .de_type - .try_as_plain_de_type() - .ok_or(DataElementDeserializeError::DuplicateIdentityDataElement)?; - (RawPlainDataElement { de_type, contents: raw_de.contents }).try_deserialize() +impl<'d, F> DeIterator<'d, F> { + pub(in crate::legacy) fn new(data: &'d [u8]) -> Self { + Self { delegate: GenericDeIterator::new(data) } } } -impl<'d, F> Iterator for PlainDeIterator<'d, F> -where - F: PacketFlavor, - actions::ActionsDataElement<F>: DataElement, -{ - type Item = Result<PlainDataElement<F>, DataElementDeserializeError>; +impl<'d, F: PacketFlavor> Iterator for DeIterator<'d, F> { + type Item = Result<DeserializedDataElement<F>, DataElementDeserializeError>; fn next(&mut self) -> Option<Self::Item> { - let parse_result = nom::combinator::cut(nom::combinator::map_res( - parse_de, - Self::raw_de_to_plain_de, + self.delegate.next() + } +} + +/// The generified innards of [DeIterator] so that it's possible to also use test-only +/// deserializers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub(in crate::legacy) struct GenericDeIterator<'d, F, D> { + /// Data to be parsed, containing a sequence of data elements in serialized + /// form. + data: &'d [u8], + _flavor_marker: PhantomData<F>, + _deser_marker: PhantomData<D>, +} + +impl<'d, F, D> GenericDeIterator<'d, F, D> { + fn new(data: &'d [u8]) -> Self { + Self { data, _flavor_marker: Default::default(), _deser_marker: Default::default() } + } +} + +impl<'d, F: PacketFlavor, D: DataElementDeserializer> Iterator for GenericDeIterator<'d, F, D> { + type Item = Result<D::Deserialized<F>, DataElementDeserializeError>; + + fn next(&mut self) -> Option<Self::Item> { + if self.data.is_empty() { + return None; + } + let parse_result = combinator::cut(combinator::map_res( + RawDataElement::parse, + D::deserialize_de, ))(self.data); - match parse_result { + + match parse_result.finish() { Ok((rem, de)) => { self.data = rem; Some(Ok(de)) } - Err(nom::Err::Error(_)) => { - panic!("All Errors are turned into Failures with `cut` above"); - } - Err(nom::Err::Failure(DataElementDeserializeError::NomError( - nom::error::ErrorKind::Eof, - ))) => { - if self.data.is_empty() { - None - } else { - Some(Err(DataElementDeserializeError::UnexpectedDataRemaining)) - } - } - Err(nom::Err::Failure(e)) => Some(Err(e)), - Err(nom::Err::Incomplete(_)) => { - panic!("Incomplete unexpected when using nom::complete APIs") - } + Err(e) => Some(Err(e)), } } } -/// A "plain" data element (not a container) without parsing the content. -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct RawPlainDataElement<'d> { - de_type: PlainDataElementType, - /// Byte array payload of the data element, without the DE header. - contents: &'d [u8], -} - -impl<'d> RawPlainDataElement<'d> { - /// Deserialize into a [PlainDataElement] to expose DE-type-specific data representations. - /// - /// Returns `None` if the contents of the raw DE can't be deserialized into the corresponding - /// DE's representation. - fn try_deserialize<F>(&self) -> Result<PlainDataElement<F>, DataElementDeserializeError> - where - F: PacketFlavor, - actions::ActionsDataElement<F>: DataElement, - { - match self.de_type { - PlainDataElementType::Actions => { - actions::ActionsDataElement::deserialize::<F>(self.contents) - .map(PlainDataElement::Actions) - } - PlainDataElementType::TxPower => { - TxPowerDataElement::deserialize::<F>(self.contents).map(PlainDataElement::TxPower) - } - } - } -} - -/// Contents of an encrypted advertisement before decryption. -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct EncryptedAdvContents<'d> { - identity_type: EncryptedIdentityDataElementType, - /// Salt from the advertisement, converted into a padder. - /// Pre-calculated so it's only derived once across multiple decrypt attempts. - salt_padder: ldt::XorPadder<{ crypto_provider::aes::BLOCK_SIZE }>, - /// The salt instance used for encryption of this advertisement. - salt: LegacySalt, - /// Ciphertext containing the metadata key and any data elements - ciphertext: &'d [u8], -} - -impl<'d> EncryptedAdvContents<'d> { - /// Try decrypting with an identity's LDT cipher and deserializing the resulting data elements. - /// - /// Returns the decrypted data if decryption and verification succeeded and the resulting DEs could be parsed - /// successfully, otherwise `Err`. - pub(crate) fn try_decrypt<C: CryptoProvider>( - &self, - cipher: &ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C>, - ) -> Result<DecryptedAdvContents, DecryptError> { - let plaintext = cipher - .decrypt_and_verify(self.ciphertext, &self.salt_padder) - .map_err(|_e| DecryptError::DecryptOrVerifyError)?; - - // plaintext starts with 14 bytes of metadata key, then DEs. - let (remaining, metadata_key) = combinator::map_res( - bytes::complete::take(NP_LEGACY_METADATA_KEY_LEN), - |slice: &[u8]| slice.try_into(), - )(plaintext.as_slice()) - .map_err(|_e: nom::Err<nom::error::Error<&[u8]>>| { - DecryptError::DeserializeError(AdvDeserializeError::AdvertisementDeserializeError) - })?; - - let remaining_arr = ArrayView::try_from_slice(remaining) - .expect("Max remaining = 31 - 14 = 17 bytes < BLE_ADV_SVC_CONTENT_LEN"); - - Ok(DecryptedAdvContents::new( - self.identity_type, - ShortMetadataKey(metadata_key), - self.salt, - remaining_arr, - )) - } -} - /// Errors that can occur decrypting encrypted advertisements. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub(crate) enum DecryptError { /// Decrypting or verifying the advertisement ciphertext failed DecryptOrVerifyError, - /// Decrypting succeeded, but deserializing from the plaintext failed - DeserializeError(AdvDeserializeError), } -impl From<AdvDeserializeError> for DecryptError { - fn from(e: AdvDeserializeError) -> Self { - DecryptError::DeserializeError(e) - } -} - -/// All v0 normal DE types with deserialized contents. -#[derive(Debug, PartialEq, Eq)] +/// All v0 DE types with deserialized contents. +#[derive(Debug, PartialEq, Eq, Clone)] #[allow(missing_docs)] -pub enum PlainDataElement<F: PacketFlavor> { +pub enum DeserializedDataElement<F: PacketFlavor> { Actions(actions::ActionsDataElement<F>), TxPower(TxPowerDataElement), } -impl<F: PacketFlavor> PlainDataElement<F> { +impl<F: PacketFlavor> DeserializedDataElement<F> { /// Returns the DE type as a u8 #[cfg(feature = "devtools")] pub fn de_type_code(&self) -> u8 { match self { - PlainDataElement::Actions(_) => DataElementType::Actions.type_code().as_u8(), - PlainDataElement::TxPower(_) => DataElementType::TxPower.type_code().as_u8(), + DeserializedDataElement::Actions(_) => ActionsDataElement::<F>::DE_TYPE_CODE.as_u8(), + DeserializedDataElement::TxPower(_) => TxPowerDataElement::DE_TYPE_CODE.as_u8(), } } /// Returns the serialized contents of the DE #[cfg(feature = "devtools")] - pub fn de_contents(&self) -> alloc::vec::Vec<u8> { - use crate::legacy::serialize::{DataElementBundle, ToDataElementBundle}; + #[allow(clippy::unwrap_used)] + pub fn de_contents(&self) -> alloc::vec::Vec<u8> + where + actions::ActionsDataElement<F>: crate::legacy::data_elements::SerializeDataElement<F>, + { + use crate::legacy::data_elements::{DataElementSerializationBuffer, SerializeDataElement}; + + let mut sink = DataElementSerializationBuffer::new(super::NP_MAX_ADV_CONTENT_LEN).unwrap(); match self { - PlainDataElement::Actions(a) => { - let bundle: DataElementBundle<F> = a.to_de_bundle(); - bundle.contents_as_slice().to_vec() - } - PlainDataElement::TxPower(t) => { - let bundle: DataElementBundle<F> = t.to_de_bundle(); - bundle.contents_as_slice().to_vec() + DeserializedDataElement::Actions(a) => a.serialize_contents(&mut sink), + DeserializedDataElement::TxPower(t) => { + SerializeDataElement::<F>::serialize_contents(t, &mut sink) } } + .unwrap(); + sink.into_inner().into_inner().as_slice().to_vec() } } -/// The contents of a plaintext advertisement after deserializing DE contents -#[derive(Debug, PartialEq, Eq)] -pub struct PlaintextAdvContents<'d> { - identity_type: PlaintextIdentityMode, - /// Contents of the advertisement excluding the identity DE - data: &'d [u8], -} - -impl<'d> PlaintextAdvContents<'d> { - /// Returns the identity type used for the advertisement - pub fn identity(&self) -> PlaintextIdentityMode { - self.identity_type - } - - /// Returns an iterator over the v0 data elements - pub fn data_elements(&self) -> PlainDeIterator<'d, Plaintext> { - PlainDeIterator { data: self.data, _marker: PhantomData } - } -} - -/// Contents of an encrypted advertisement after decryption and deserializing DEs. +/// Contents of an LDT advertisement after decryption. #[derive(Debug, PartialEq, Eq)] pub struct DecryptedAdvContents { - identity_type: EncryptedIdentityDataElementType, - metadata_key: ShortMetadataKey, - salt: LegacySalt, - /// The decrypted data in this advertisement. This should be a sequence of - /// serialized data elements, excluding the identity DE. - data: ArrayView<u8, { BLE_ADV_SVC_CONTENT_LEN }>, + identity_token: V0IdentityToken, + salt: V0Salt, + /// The decrypted data in this advertisement after the identity token. + /// This is hopefully a sequence of serialized data elements, but that hasn't been validated + /// yet at construction time. + data: ArrayView<u8, { NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN }>, } impl DecryptedAdvContents { /// Returns a new DecryptedAdvContents with the provided contents. fn new( - identity_type: EncryptedIdentityDataElementType, - metadata_key: ShortMetadataKey, - salt: LegacySalt, - data: ArrayView<u8, { BLE_ADV_SVC_CONTENT_LEN }>, + metadata_key: V0IdentityToken, + salt: V0Salt, + data: ArrayView<u8, { NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN }>, ) -> Self { - Self { identity_type, metadata_key, salt, data } - } - - /// The type of identity DE used in the advertisement. - pub fn identity_type(&self) -> EncryptedIdentityDataElementType { - self.identity_type + Self { identity_token: metadata_key, salt, data } } /// Iterator over the data elements in an advertisement, except for any DEs related to resolving /// the identity or otherwise validating the payload (e.g. any identity DEs like Private /// Identity). - pub fn data_elements(&self) -> PlainDeIterator<Ciphertext> { - PlainDeIterator { data: self.data.as_slice(), _marker: PhantomData } + pub fn data_elements(&self) -> DeIterator<Ciphertext> { + DeIterator::new(self.data.as_slice()) } /// The salt used for decryption of this advertisement. - pub fn salt(&self) -> LegacySalt { + pub fn salt(&self) -> V0Salt { self.salt } + + #[cfg(test)] + pub(in crate::legacy) fn generic_data_elements<D: DataElementDeserializer>( + &self, + ) -> GenericDeIterator<Ciphertext, D> { + GenericDeIterator::new(self.data.as_slice()) + } } impl HasIdentityMatch for DecryptedAdvContents { type Version = V0; - fn metadata_key(&self) -> ShortMetadataKey { - self.metadata_key + fn identity_token(&self) -> V0IdentityToken { + self.identity_token } } -/// The contents of an advertisement after plaintext DEs, if any, have been deserialized, but -/// before any decryption is done. -#[derive(Debug, PartialEq, Eq)] -pub(crate) enum IntermediateAdvContents<'d> { - /// Plaintext advertisements - Plaintext(PlaintextAdvContents<'d>), - /// Ciphertext advertisements - Ciphertext(EncryptedAdvContents<'d>), +/// Overall strategy for deserializing adv contents (once decrypted, if applicable) into data +/// elements +pub(in crate::legacy) trait DataElementDeserializer: Sized { + /// Disambiguates the intermediate form of a DE + type DeTypeDisambiguator: Copy; + /// The fully deserialized form of a DE + type Deserialized<F: PacketFlavor>: fmt::Debug + PartialEq + Eq + Clone; + + /// Map the encoded len found in a DE header to the actual len that should be consumed from the + /// advertisement payload + fn map_encoded_len_to_actual_len( + de_type: DeTypeCode, + encoded_len: DeEncodedLength, + ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError>; + + /// Deserialize into a [Self::Deserialized] to expose DE-type-specific data representations. + /// + /// Returns `Err` if the contents of the raw DE can't be deserialized into the corresponding + /// DE's representation. + fn deserialize_de<F: PacketFlavor>( + raw_de: RawDataElement<Self>, + ) -> Result<Self::Deserialized<F>, DataElementDeserializeError>; +} + +/// Possible errors when mapping DE encoded lengths to actual lengths +pub(in crate::legacy) enum LengthError { + /// The DE type was known, but the encoded length was invalid + InvalidLength, + /// The DE type was not unrecognized + InvalidType, +} + +impl From<DeLengthOutOfRange> for LengthError { + fn from(_value: DeLengthOutOfRange) -> Self { + Self::InvalidLength + } +} + +/// The default deserialization strategy that maps type codes to [DataElementType], and deserializes +/// to [DeserializedDataElement]. +#[derive(Debug, PartialEq, Eq, Clone)] +struct StandardDeserializer; + +impl DataElementDeserializer for StandardDeserializer { + type DeTypeDisambiguator = DataElementType; + type Deserialized<F: PacketFlavor> = DeserializedDataElement<F>; + + fn map_encoded_len_to_actual_len( + de_type: DeTypeCode, + encoded_len: DeEncodedLength, + ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError> { + match de_type { + TxPowerDataElement::DE_TYPE_CODE => { + <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) + .map_err(|e| e.into()) + .map(|l| (DataElementType::TxPower, l)) + } + ActionsDataElement::<Plaintext>::DE_TYPE_CODE => { + <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) + .map_err(|e| e.into()) + .map(|l| (DataElementType::Actions, l)) + } + _ => Err(LengthError::InvalidType), + } + } + + fn deserialize_de<F: PacketFlavor>( + raw_de: RawDataElement<Self>, + ) -> Result<Self::Deserialized<F>, DataElementDeserializeError> { + match raw_de.de_type { + DataElementType::Actions => { + actions::ActionsDataElement::deserialize::<F>(raw_de.contents) + .map(DeserializedDataElement::Actions) + } + DataElementType::TxPower => TxPowerDataElement::deserialize::<F>(raw_de.contents) + .map(DeserializedDataElement::TxPower), + } + } }
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/tests.rs b/nearby/presence/np_adv/src/legacy/deserialize/tests.rs deleted file mode 100644 index 3dfecd1..0000000 --- a/nearby/presence/np_adv/src/legacy/deserialize/tests.rs +++ /dev/null
@@ -1,818 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(unused_results, clippy::unwrap_used)] - -extern crate alloc; -extern crate std; - -use super::*; -use crate::{ - credential::{v0::V0, SimpleBroadcastCryptoMaterial}, - de_type::IdentityDataElementType, - legacy::{ - actions::{self, ActionBits, ActionsDataElement, Finder, NearbyShare}, - de_type::DeActualLength, - random_data_elements::{random_de_ciphertext, random_de_plaintext}, - serialize::{ - encode_de_header_actual_len, id_de_type_as_generic_de_type, AdvBuilder, - DataElementBundle, Identity, LdtIdentity, ToDataElementBundle, - }, - PacketFlavorEnum, BLE_ADV_SVC_CONTENT_LEN, - }, - parse_adv_header, shared_data, - shared_data::TxPower, - AdvHeader, PublicIdentity, -}; -use alloc::vec::Vec; -use array_view::ArrayView; -use crypto_provider_default::CryptoProviderImpl; -use ldt_np_adv::LdtEncrypterXtsAes128; -use nom::error::{self, ErrorKind}; -use rand_ext::rand::{prelude::SliceRandom, Rng as _}; -use std::vec; -use strum::IntoEnumIterator as _; - -#[test] -fn parse_empty_raw_adv() { - let adv_data = parse_raw_adv_contents::<CryptoProviderImpl>(&[]); - assert_eq!(AdvDeserializeError::MissingIdentity, adv_data.unwrap_err()); -} - -#[test] -fn parse_raw_adv_1_de_long_private_identity() { - // 3 bytes of payload after metadata key - let adv = parse_raw_adv_contents::<CryptoProviderImpl>(&[ - 0x31, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, - 0x0F, 0x10, 0x11, 0x12, 0x13, - ]) - .unwrap(); - assert_eq!( - RawAdvertisement::Ciphertext(EncryptedAdvContents { - identity_type: EncryptedIdentityDataElementType::Private, - salt_padder: ldt_np_adv::salt_padder::<16, CryptoProviderImpl>( - ldt_np_adv::LegacySalt::from([0x01, 0x02]) - ), - salt: ldt_np_adv::LegacySalt::from([0x01, 0x02]), - ciphertext: &[ - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13 - ] - }), - adv - ); -} - -#[test] -fn parse_raw_adv_3_de_public_identity() { - let adv = parse_raw_adv_contents::<CryptoProviderImpl>(&[ - 0x03, // public identity - 0x15, 0x05, // tx power 5 - 0x26, 0x00, 0x44, // actions - ]) - .unwrap(); - match adv { - RawAdvertisement::Plaintext(plaintext) => { - assert_eq!(PlaintextIdentityMode::Public, plaintext.identity_type); - let mut action_bits = ActionBits::default(); - action_bits.set_action(NearbyShare::from(true)); - action_bits.set_action(Finder::from(true)); - assert_eq!( - vec![ - PlainDataElement::<Plaintext>::TxPower(TxPowerDataElement::from( - TxPower::try_from(5).unwrap() - )), - PlainDataElement::Actions(ActionsDataElement::from(action_bits)), - ], - plaintext.data_elements().collect::<Result<Vec<_>, _>>().unwrap(), - ); - } - RawAdvertisement::Ciphertext(_) => panic!("adv should be plaintext"), - } -} - -#[test] -fn parse_raw_adv_0_de_public_identity() { - let adv = parse_raw_adv_contents::<CryptoProviderImpl>(&[ - 0x03, // public identity - ]) - .unwrap(); - match adv { - RawAdvertisement::Plaintext(plaintext) => { - assert_eq!(PlaintextIdentityMode::Public, plaintext.identity_type); - assert_eq!( - Vec::<PlainDataElement<Plaintext>>::new(), - plaintext.data_elements().collect::<Result<Vec<_>, _>>().unwrap() - ); - } - RawAdvertisement::Ciphertext(_) => panic!("adv should be plaintext"), - } -} - -#[test] -fn parse_raw_adv_1_de_length_overrun() { - // battery uses the header length as is - let input = &[0xFB, 0x01, 0x02, 0x03]; - assert_eq!( - nom::Err::Error(DataElementDeserializeError::NomError(ErrorKind::MapOpt)), - parse_de(input).unwrap_err(), - ); -} - -#[test] -fn parse_raw_adv_public_identity_containing_public_identity() { - let input = &[ - 0x03, // public identity - 0x03, // another public identity - 0x15, 0x03, // tx power de - ]; - match parse_raw_adv_contents::<CryptoProviderImpl>(input).unwrap() { - RawAdvertisement::Plaintext(content) => { - assert_eq!( - DataElementDeserializeError::DuplicateIdentityDataElement, - content.data_elements().collect::<Result<Vec<_>, _>>().unwrap_err(), - ); - } - RawAdvertisement::Ciphertext(_) => panic!("Adv should be plaintext"), - } -} - -#[test] -fn parse_raw_adv_no_identity_containing_public_identity() { - let input = &[ - 0x15, 0x03, // tx power de - 0x03, // public identity -- since it's not the first, this is a no identity adv - 0x15, 0x03, // tx power de - ]; - assert_eq!( - AdvDeserializeError::MissingIdentity, - parse_raw_adv_contents::<CryptoProviderImpl>(input).unwrap_err() - ); -} - -#[test] -fn parse_raw_adv_1_de_long_private_identity_with_another_top_level_de() { - let input = &[ - 0x31, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, - 0x0F, 0x10, 0x11, 0x12, 0x13, // private identity - 0x15, 0x03, // tx power de - ]; - assert_eq!( - AdvDeserializeError::TooManyTopLevelDataElements, - parse_raw_adv_contents::<CryptoProviderImpl>(input).unwrap_err() - ); -} - -#[test] -fn parse_raw_adv_private_identity_ciphertext_min_length() { - let short_input = &[ - // private identity w/ salt, len = 1 - 0x11, 0x10, 0x11, // 15 ciphertext bytes, + 2 salt = 17 total - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - ]; - assert_eq!( - AdvDeserializeError::AdvertisementDeserializeError, - parse_raw_adv_contents::<CryptoProviderImpl>(short_input).unwrap_err() - ); - - let ok_input = &[ - // private identity w/ salt - 0x21, 0x10, 0x11, // 16 ciphertext bytes, 18 bytes total de len, encoded len 2 - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, - ]; - assert_eq!( - RawAdvertisement::Ciphertext(EncryptedAdvContents { - identity_type: EncryptedIdentityDataElementType::Private, - salt: [0x10, 0x11].into(), - salt_padder: ldt_np_adv::salt_padder::<16, CryptoProviderImpl>([0x10, 0x11].into()), - ciphertext: &ok_input[3..] - }), - parse_raw_adv_contents::<CryptoProviderImpl>(ok_input).unwrap() - ); -} - -#[test] -fn parse_raw_adv_private_identity_ciphertext_too_long() { - let long_input = &[ - // private identity w/ salt, len = 7 - 0x71, 0x10, 0x11, // 21 ciphertext bytes, + 2 salt - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, - ]; - assert_eq!( - AdvDeserializeError::AdvertisementDeserializeError, - parse_raw_adv_contents::<CryptoProviderImpl>(long_input).unwrap_err() - ); - - // removing 1 byte makes it work - let ok_input = &[ - // private identity w/ salt, len = 6 - 0x61, 0x10, 0x11, // 20 ciphertext bytes, + 2 salt - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, - ]; - assert_eq!( - RawAdvertisement::Ciphertext(EncryptedAdvContents { - identity_type: EncryptedIdentityDataElementType::Private, - salt_padder: ldt_np_adv::salt_padder::<16, CryptoProviderImpl>([0x10, 0x11].into()), - salt: [0x10, 0x11].into(), - ciphertext: &ok_input[3..] - }), - parse_raw_adv_contents::<CryptoProviderImpl>(ok_input).unwrap() - ); -} - -/// Test method body that creates an array, deserializes it into a DE, serializes it, -/// and asserts that the same bytes are produced. -/// -/// Evaluates to the deserialized DE. -macro_rules! de_roundtrip_test { - ($de_type:ty, $type_variant:ident, $de_variant:ident, $flavor:ty, $bytes:expr) => {{ - let parsed_de_enum = parse_plain_de::<$flavor>(PlainDataElementType::$type_variant, $bytes); - if let PlainDataElement::$de_variant(de) = parsed_de_enum { - let expected = <$de_type>::deserialize::<$flavor>($bytes).unwrap(); - assert_eq!(expected, de); - - let de_bundle: DataElementBundle<$flavor> = de.to_de_bundle(); - assert_eq!($bytes, de_bundle.contents_as_slice()); - - de - } else { - panic!("Unexpected variant: {:?}", parsed_de_enum); - } - }}; -} - -#[test] -fn actions_de_contents_roundtrip_plaintext() { - let actions = actions::tests::all_plaintext_actions(); - let bundle = actions::ActionsDataElement::from(actions).to_de_bundle(); - - de_roundtrip_test!( - actions::ActionsDataElement::<Plaintext>, - Actions, - Actions, - Plaintext, - bundle.contents_as_slice() - ); -} - -#[test] -fn actions_de_contents_roundtrip_ciphertext() { - let actions = actions::tests::all_ciphertext_actions(); - let bundle = actions::ActionsDataElement::from(actions).to_de_bundle(); - - de_roundtrip_test!( - actions::ActionsDataElement::<Ciphertext>, - Actions, - Actions, - Ciphertext, - bundle.contents_as_slice() - ); -} - -#[test] -fn tx_power_de_contents_roundtrip_plaintext() { - let tx = shared_data::TxPower::try_from(-10).unwrap(); - let bundle: DataElementBundle<Plaintext> = TxPowerDataElement::from(tx).to_de_bundle(); - - de_roundtrip_test!(TxPowerDataElement, TxPower, TxPower, Plaintext, bundle.contents_as_slice()); -} - -#[test] -fn tx_power_de_contents_roundtrip_ciphertext() { - let tx = shared_data::TxPower::try_from(-10).unwrap(); - let bundle: DataElementBundle<Ciphertext> = TxPowerDataElement::from(tx).to_de_bundle(); - - de_roundtrip_test!( - TxPowerDataElement, - TxPower, - TxPower, - Ciphertext, - bundle.contents_as_slice() - ); -} - -#[test] -fn parse_de_invalid_de_len_error() { - let input = &[ - // bogus 6-byte battery de -- only allows length = 3 - 0x6B, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - ]; - - assert_eq!( - nom::Err::Error(DataElementDeserializeError::NomError(ErrorKind::MapOpt)), - parse_de(&input[..]).unwrap_err() - ); -} - -#[test] -fn raw_de_to_plain_de_matches_plain_des() { - assert_eq!( - PlainDataElement::TxPower(TxPowerDataElement::from(TxPower::try_from(1).unwrap())), - PlainDeIterator::<Plaintext>::raw_de_to_plain_de(RawDataElement { - de_type: DataElementType::TxPower, - contents: &[0x01] - }) - .unwrap(), - ); - assert_eq!( - PlainDataElement::Actions(ActionsDataElement::from( - ActionBits::try_from(0x00400000).unwrap() - )), - PlainDeIterator::<Plaintext>::raw_de_to_plain_de(RawDataElement { - de_type: DataElementType::Actions, - contents: &[0x00, 0x40] - }) - .unwrap(), - ); -} - -#[test] -fn raw_de_to_plain_de_rejects_identity_de_error() { - for idet in IdentityDataElementType::iter() { - assert_eq!( - DataElementDeserializeError::DuplicateIdentityDataElement, - PlainDeIterator::<Plaintext>::raw_de_to_plain_de(RawDataElement { - de_type: id_de_type_as_generic_de_type(idet), - contents: &[0x02], - }) - .unwrap_err() - ); - } -} - -#[test] -fn parse_encrypted_identity_contents_too_short_error() { - // 2 byte salt + 15 byte ciphertext: 1 too short - let mut input = [0u8; 17]; - for (pos, e) in input.iter_mut().enumerate() { - *e = pos as u8 - } - assert_eq!( - nom::Err::Error(error::Error { input: &input[2..], code: error::ErrorKind::TakeWhileMN }), - parse_encrypted_identity_de_contents(&input).unwrap_err() - ); -} - -#[test] -fn parse_encrypted_identity_contents_ok() { - // 2 byte salt + minimum 16 byte ciphertext - let mut input = [0u8; 18]; - for (pos, e) in input.iter_mut().enumerate() { - *e = pos as u8 - } - assert_eq!( - ([].as_slice(), (ldt_np_adv::LegacySalt::from([0, 1]), &input[2..])), - parse_encrypted_identity_de_contents(&input).unwrap() - ); -} - -#[test] -fn deserialize_adv_public_identity_empty_des() { - let input = &[ - 0x03, // public identity - ]; - assert_eq!( - AdvDeserializeError::NoPublicDataElements, - deserialize_adv_contents::<CryptoProviderImpl>(input).unwrap_err() - ); -} - -#[test] -fn plaintext_random_adv_contents_round_trip_public() { - plaintext_random_adv_contents_round_trip(PublicIdentity::default, PlaintextIdentityMode::Public) -} - -#[test] -fn ciphertext_random_adv_contents_round_trip() { - let mut rng = rand_ext::seeded_rng(); - let de_types: Vec<PlainDataElementType> = PlainDataElementType::iter() - .filter(|t| t.supports_flavor(PacketFlavorEnum::Ciphertext)) - .collect(); - let identity_de_types: Vec<EncryptedIdentityDataElementType> = - EncryptedIdentityDataElementType::iter().collect(); - - for _ in 0..10_000 { - let mut des = Vec::new(); - - let identity_type = *identity_de_types.choose(&mut rng).unwrap(); - let key_seed: [u8; 32] = rng.gen(); - let salt: ldt_np_adv::LegacySalt = rng.gen::<[u8; 2]>().into(); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = rng.gen(); - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key); - let cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac); - - let metadata_key = ShortMetadataKey(metadata_key); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); - - let mut builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - identity_type, - salt, - &broadcast_cm, - )); - - loop { - let de_type = *de_types.choose(&mut rng).unwrap(); - let (de, bundle) = random_de_ciphertext(de_type, &mut rng).unwrap(); - - if builder.add_data_element(bundle.clone()).ok().is_none() { - // out of room - if des.is_empty() { - // need at least one, so try again - continue; - } else { - // there's at least one so proceed to serialization - break; - } - } - - des.push(de); - } - - let serialized = builder.into_advertisement().unwrap(); - let (remaining, header) = parse_adv_header(serialized.as_slice()).unwrap(); - let parsed_adv = deserialize_adv_contents::<CryptoProviderImpl>(remaining).unwrap(); - - assert_eq!(AdvHeader::V0, header); - if let IntermediateAdvContents::Ciphertext(eac) = parsed_adv { - assert_eq!( - EncryptedAdvContents { - identity_type, - salt_padder: ldt_np_adv::salt_padder::<16, CryptoProviderImpl>(salt), - salt, - // skip adv header, de header, salt - ciphertext: &serialized.as_slice()[4..] - }, - eac - ); - - let contents = eac.try_decrypt(&cipher).unwrap(); - assert_eq!(identity_type, contents.identity_type); - assert_eq!(metadata_key, contents.metadata_key); - assert_eq!(salt, contents.salt); - assert_eq!(des, contents.data_elements().collect::<Result<Vec<_>, _>>().unwrap()); - } else { - panic!("Unexpected variant: {:?}", parsed_adv); - } - } -} - -#[test] -fn decrypt_and_deserialize_ciphertext_adv_canned() { - let key_seed = [0x11_u8; 32]; - let salt: ldt_np_adv::LegacySalt = [0x22; 2].into(); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key); - let cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac); - - let metadata_key = ShortMetadataKey(metadata_key); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); - - let mut builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - EncryptedIdentityDataElementType::Private, - salt, - &broadcast_cm, - )); - - let tx = shared_data::TxPower::try_from(3).unwrap(); - builder.add_data_element(TxPowerDataElement::from(tx)).unwrap(); - - let serialized = builder.into_advertisement().unwrap(); - - assert_eq!( - &[ - 0x0, // adv header - 0x21, // private DE - 0x22, 0x22, // salt - // ciphertext - 0x85, 0xBF, 0xA8, 0x83, 0x58, 0x7C, 0x50, 0xCF, 0x98, 0x38, 0xA7, 0x8A, 0xC0, 0x1C, - 0x96, 0xF9 - ], - serialized.as_slice() - ); - - let (remaining, header) = parse_adv_header(serialized.as_slice()).unwrap(); - assert_eq!(AdvHeader::V0, header); - - let parsed_adv = deserialize_adv_contents::<CryptoProviderImpl>(remaining).unwrap(); - if let IntermediateAdvContents::Ciphertext(eac) = parsed_adv { - assert_eq!( - EncryptedAdvContents { - identity_type: EncryptedIdentityDataElementType::Private, - salt_padder: ldt_np_adv::salt_padder::<16, CryptoProviderImpl>(salt), - salt, - // skip adv header, de header, salt - ciphertext: &serialized.as_slice()[4..] - }, - eac - ); - - let decrypted = eac.try_decrypt(&cipher).unwrap(); - assert_eq!(EncryptedIdentityDataElementType::Private, decrypted.identity_type); - assert_eq!(metadata_key, decrypted.metadata_key); - assert_eq!(salt, decrypted.salt); - assert_eq!( - vec![PlainDataElement::TxPower(TxPowerDataElement::from( - TxPower::try_from(3).unwrap() - ))], - decrypted.data_elements().collect::<Result<Vec<_>, _>>().unwrap() - ); - } else { - panic!("Unexpected variant: {:?}", parsed_adv); - } -} - -#[test] -fn decrypt_and_deserialize_plaintext_adv_canned() { - let mut builder = AdvBuilder::new(PublicIdentity); - - let actions = ActionBits::default(); - builder.add_data_element(ActionsDataElement::from(actions)).unwrap(); - - let serialized = builder.into_advertisement().unwrap(); - - assert_eq!( - &[ - 0x0, // adv header - 0x03, // public DE - 0x16, 0x00 // actions - ], - serialized.as_slice() - ); - - let (remaining, header) = parse_adv_header(serialized.as_slice()).unwrap(); - assert_eq!(AdvHeader::V0, header); - - let parsed_adv = deserialize_adv_contents::<CryptoProviderImpl>(remaining).unwrap(); - if let IntermediateAdvContents::Plaintext(adv_contents) = parsed_adv { - assert_eq!(PlaintextIdentityMode::Public, adv_contents.identity()); - assert_eq!( - vec![PlainDataElement::<Plaintext>::Actions(ActionsDataElement::from( - ActionBits::default() - ))], - adv_contents.data_elements().collect::<Result<Vec<_>, _>>().unwrap() - ); - } else { - panic!("Unexpected variant: {:?}", parsed_adv); - } -} - -#[test] -fn decrypt_with_wrong_key_seed_error() { - let salt = ldt_np_adv::LegacySalt::from([0x22; 2]); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - let correct_key_seed = [0x11_u8; 32]; - - let (adv_content, correct_cipher) = - build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); - let eac = parse_ciphertext_adv_contents(&correct_cipher, &adv_content.as_slice()[1..]); - - // wrong key seed doesn't work (derives wrong ldt key, wrong hmac key) - let wrong_key_seed_cipher = { - let key_seed = [0x22_u8; 32]; - - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key); - ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac) - }; - - assert_eq!( - DecryptError::DecryptOrVerifyError, - eac.try_decrypt(&wrong_key_seed_cipher,).unwrap_err() - ); -} - -#[test] -fn decrypt_with_wrong_hmac_key_error() { - let salt = ldt_np_adv::LegacySalt::from([0x22; 2]); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - let correct_key_seed = [0x11_u8; 32]; - - let (adv_content, correct_cipher_config) = - build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); - let eac = parse_ciphertext_adv_contents(&correct_cipher_config, &adv_content.as_slice()[1..]); - - let wrong_hmac_key_cipher = { - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&[0x10_u8; 32]); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key); - - ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac) - }; - - assert_eq!( - DecryptError::DecryptOrVerifyError, - eac.try_decrypt::<CryptoProviderImpl>(&wrong_hmac_key_cipher,).unwrap_err() - ); -} - -#[test] -fn decrypt_with_wrong_hmac_error() { - let salt = ldt_np_adv::LegacySalt::from([0x22; 2]); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - let correct_key_seed = [0x11_u8; 32]; - - let (adv_content, correct_cipher_config) = - build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); - let eac = parse_ciphertext_adv_contents(&correct_cipher_config, &adv_content.as_slice()[1..]); - - let wrong_hmac_key_cipher = { - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&correct_key_seed); - - ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, [0x77; 32]) - }; - - assert_eq!( - DecryptError::DecryptOrVerifyError, - eac.try_decrypt(&wrong_hmac_key_cipher,).unwrap_err() - ); -} - -#[test] -fn decrypt_and_deserialize_ciphertext_with_public_adv_inside_error() { - let key_seed = [0x11_u8; 32]; - let salt: ldt_np_adv::LegacySalt = [0x22; 2].into(); - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let ldt_key = hkdf.legacy_ldt_key(); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key); - let cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac); - - let mut plaintext = vec![]; - plaintext.extend_from_slice(&metadata_key); - - let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap()); - - plaintext.push( - encode_de_header_actual_len(DataElementType::TxPower, 1u8.try_into().unwrap()).unwrap(), - ); - - let plaintext_de_bundle: DataElementBundle<Plaintext> = txpower_de.to_de_bundle(); - plaintext.extend_from_slice(plaintext_de_bundle.contents_as_slice()); - // forge an otherwise impossible to express public identity - plaintext.push( - encode_de_header_actual_len(DataElementType::PublicIdentity, DeActualLength::ZERO).unwrap(), - ); - - assert_eq!(17, plaintext.len()); - - let ldt = LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&ldt_key); - ldt.encrypt(&mut plaintext, &ldt_np_adv::salt_padder::<16, CryptoProviderImpl>(salt)).unwrap(); - let ciphertext = plaintext; - - let mut adv = vec![]; - adv.push(0x00); // adv header - adv.push( - encode_de_header_actual_len( - DataElementType::PrivateIdentity, - (2 + ciphertext.len()).try_into().unwrap(), - ) - .unwrap(), - ); // private DE - adv.extend_from_slice(&[0x22; 2]); // salt - adv.extend_from_slice(&ciphertext); - - let parsed_adv = deserialize_adv_contents::<CryptoProviderImpl>(&adv[1..]).unwrap(); - if let IntermediateAdvContents::Ciphertext(eac) = parsed_adv { - assert_eq!( - DataElementDeserializeError::DuplicateIdentityDataElement, - eac.try_decrypt(&cipher) - .unwrap() - .data_elements() - .collect::<Result<Vec<_>, _>>() - .unwrap_err() - ) - } else { - panic!("Unexpected variant: {:?}", parsed_adv); - } -} - -fn build_ciphertext_adv_contents<C: CryptoProvider>( - salt: ldt_np_adv::LegacySalt, - metadata_key: &[u8; 14], - correct_key_seed: [u8; 32], -) -> (ArrayView<u8, { BLE_ADV_SVC_CONTENT_LEN }>, ldt_np_adv::LdtNpAdvDecrypterXtsAes128<C>) { - let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&correct_key_seed); - - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(metadata_key.as_slice()); - - let correct_cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac); - - let broadcast_cm = - SimpleBroadcastCryptoMaterial::<V0>::new(correct_key_seed, ShortMetadataKey(*metadata_key)); - - let mut builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - EncryptedIdentityDataElementType::Private, - salt, - &broadcast_cm, - )); - builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); - (builder.into_advertisement().unwrap(), correct_cipher) -} - -fn parse_ciphertext_adv_contents<'b>( - cipher: &ldt_np_adv::LdtNpAdvDecrypterXtsAes128<CryptoProviderImpl>, - adv_content: &'b [u8], -) -> EncryptedAdvContents<'b> { - let eac = match deserialize_adv_contents::<CryptoProviderImpl>(adv_content).unwrap() { - IntermediateAdvContents::Plaintext(_) => panic!(), - // quick confirmation that we did get something - IntermediateAdvContents::Ciphertext(eac) => eac, - }; - - // correct cipher works - assert!(eac.try_decrypt(cipher).is_ok()); - - eac -} - -/// Construct the serialized DE and parse it -fn parse_plain_de<F>(de_type: PlainDataElementType, contents: &[u8]) -> PlainDataElement<F> -where - F: PacketFlavor, - actions::ActionsDataElement<F>: DataElement, -{ - let mut buf = vec![]; - buf.push( - encode_de_header_actual_len( - de_type.as_generic_de_type(), - contents.len().try_into().unwrap(), - ) - .unwrap(), - ); - buf.extend_from_slice(contents); - - let mut plain_des = PlainDeIterator { data: &buf, _marker: PhantomData } - .collect::<Result<Vec<_>, _>>() - .unwrap(); - assert_eq!(1, plain_des.len()); - plain_des.swap_remove(0) -} - -fn plaintext_random_adv_contents_round_trip<I: Identity<Flavor = Plaintext>, F: Fn() -> I>( - mk_identity: F, - identity_type: PlaintextIdentityMode, -) { - let mut rng = rand_ext::seeded_rng(); - let de_types: Vec<PlainDataElementType> = PlainDataElementType::iter() - .filter(|t| t.supports_flavor(PacketFlavorEnum::Plaintext)) - .collect(); - - for _ in 0..10_000 { - let mut de_tuples = Vec::new(); - let mut builder = AdvBuilder::new(mk_identity()); - - loop { - let de_type = *de_types.choose(&mut rng).unwrap(); - let (de, bundle) = random_de_plaintext(de_type, &mut rng).unwrap(); - - if builder.add_data_element(bundle.clone()).ok().is_none() { - // out of room - break; - } - - de_tuples.push((de, de_type, bundle)); - } - - let serialized = builder.into_advertisement().unwrap(); - - let (_rem, header) = - combinator::all_consuming(parse_adv_header)(&serialized.as_slice()[..1]).unwrap(); - let parsed_adv = - parse_raw_adv_contents::<CryptoProviderImpl>(&serialized.as_slice()[1..]).unwrap(); - - assert_eq!(AdvHeader::V0, header); - if let RawAdvertisement::Plaintext(adv_contents) = parsed_adv { - assert_eq!(identity_type, adv_contents.identity_type); - assert_eq!( - de_tuples.into_iter().map(|(de, _de_type, _bundle)| de).collect::<Vec<_>>(), - adv_contents.data_elements().collect::<Result<Vec<_>, _>>().unwrap(), - ); - } else { - panic!("Unexpected variant: {:?}", parsed_adv); - } - } -}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/tests/error_conditions.rs b/nearby/presence/np_adv/src/legacy/deserialize/tests/error_conditions.rs new file mode 100644 index 0000000..8230548 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/tests/error_conditions.rs
@@ -0,0 +1,321 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod unencrypted { + use crypto_provider_default::CryptoProviderImpl; + + use crate::header::V0Encoding; + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement, ActiveUnlock}; + use crate::legacy::data_elements::de_type::{DeEncodedLength, DeTypeCode}; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::data_elements::{DataElementDeserializeError, DeserializeDataElement}; + use crate::legacy::deserialize::intermediate::IntermediateAdvContents; + use crate::legacy::serialize::tests::serialize; + use crate::legacy::{Ciphertext, PacketFlavorEnum, Plaintext}; + + #[test] + fn iterate_tx_power_invalid_de_len_error() { + assert_deser_error( + // bogus 6-byte tx power de -- only allows length = 1 + &[0x65, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06], + DataElementDeserializeError::InvalidDeLength { + de_type: TxPowerDataElement::DE_TYPE_CODE, + len: DeEncodedLength::from(6), + }, + ); + } + + #[test] + fn iterate_tx_power_invalid_power_error() { + assert_deser_error( + // power too high + &[0x15, 0x7F], + DataElementDeserializeError::DeserializeError { + de_type: TxPowerDataElement::DE_TYPE_CODE, + }, + ); + } + + #[test] + fn iterate_actions_invalid_de_len_error() { + assert_deser_error( + // bogus 0-byte actions de + &[0x06], + DataElementDeserializeError::InvalidDeLength { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + len: DeEncodedLength::from(0), + }, + ); + } + + #[test] + fn iterate_actions_ciphertext_only_bit_error() { + let mut bits = ActionBits::default(); + bits.set_action(ActiveUnlock::from(true)); + assert_deser_error( + serialize(&ActionsDataElement::<Ciphertext>::from(bits)).as_slice(), + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Plaintext, + }, + ); + } + + #[test] + fn iterate_invalid_de_type_error() { + assert_deser_error( + &[0x0F], + DataElementDeserializeError::InvalidDeType { + de_type: DeTypeCode::try_from(0x0F).unwrap(), + }, + ); + } + + #[test] + fn iterate_truncated_contents_error() { + assert_deser_error( + // length 3, but only 2 bytes provided + &[0x36, 0x01, 0x02], + DataElementDeserializeError::InvalidStructure, + ); + } + + fn assert_deser_error(input: &[u8], err: DataElementDeserializeError) { + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + input, + ) + .unwrap(); + + assert_eq!( + err, + contents.as_unencrypted().unwrap().data_elements().next().unwrap().unwrap_err() + ); + } +} + +mod ldt { + + // see unencrypted tests above for basic things that are the same between unencrypted and ldt, + // like how an invalid de type is handled + + use crate::credential::matched::HasIdentityMatch; + use crate::credential::v0::V0BroadcastCredential; + use crate::header::V0Encoding; + use crate::legacy::data_elements::actions::tests::PlaintextOnly; + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement}; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::data_elements::{DataElementDeserializeError, DeserializeDataElement}; + use crate::legacy::deserialize::intermediate::IntermediateAdvContents; + use crate::legacy::deserialize::DecryptError; + use crate::legacy::serialize::{AdvBuilder, LdtEncoder}; + use crate::legacy::{Ciphertext, PacketFlavorEnum}; + use crate::shared_data::TxPower; + use alloc::vec::Vec; + use crypto_provider_default::CryptoProviderImpl; + use ldt_np_adv::{ + build_np_adv_decrypter, AuthenticatedNpLdtDecryptCipher, V0IdentityToken, V0Salt, + V0_IDENTITY_TOKEN_LEN, + }; + + #[test] + fn iterate_actions_invalid_flavor_error() { + let mut bits = ActionBits::default(); + bits.set_action(PlaintextOnly::from(true)); + + let key_seed = [0; 32]; + let identity_token = V0IdentityToken::from([0x33; V0_IDENTITY_TOKEN_LEN]); + let salt = V0Salt::from([0x01, 0x02]); + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + builder.add_data_element(ActionsDataElement::from(bits)).unwrap(); + + let adv = builder.into_advertisement().unwrap(); + + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + &adv.as_slice()[1..], + ) + .unwrap(); + let ldt = contents.as_ldt().unwrap(); + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let identity_token_hmac: [u8; 32] = hkdf + .v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()); + let decrypter = + ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, identity_token_hmac); + let decrypted = ldt.try_decrypt(&decrypter).unwrap(); + + assert_eq!(salt, decrypted.salt()); + assert_eq!(identity_token, decrypted.identity_token()); + + assert_eq!( + DataElementDeserializeError::FlavorNotSupported { + de_type: ActionsDataElement::<Ciphertext>::DE_TYPE_CODE, + flavor: PacketFlavorEnum::Ciphertext, + }, + decrypted.data_elements().next().unwrap().unwrap_err() + ) + } + + #[test] + fn decrypter_wrong_identity_token_hmac_no_match() { + build_and_deser_with_invalid_decrypter_error( + |adv| adv, + |key_seed, _identity_token| { + ldt_np_adv::build_np_adv_decrypter_from_key_seed( + &np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed), + [0xFA; 32], + ) + }, + ) + } + + #[test] + fn decrypter_wrong_key_seed_no_match() { + build_and_deser_with_invalid_decrypter_error( + |adv| adv, + |key_seed, identity_token| { + let correct_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed); + ldt_np_adv::build_np_adv_decrypter_from_key_seed( + // wrong key seed + &np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&[0xFA; 32]), + correct_hkdf + .v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()), + ) + }, + ) + } + + #[test] + fn decrypter_wrong_ldt_key_no_match() { + build_and_deser_with_invalid_decrypter_error( + |adv| adv, + |key_seed, identity_token| { + let hkdf = &np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed); + let bogus_key = ldt::LdtKey::from_concatenated(&[0xFA; 64]); + build_np_adv_decrypter( + &bogus_key, + hkdf.v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()), + hkdf.v0_identity_token_hmac_key(), + ) + }, + ) + } + + #[test] + fn decrypter_wrong_identity_token_hmac_key_no_match() { + build_and_deser_with_invalid_decrypter_error( + |adv| adv, + |key_seed, identity_token| { + let hkdf = &np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed); + build_np_adv_decrypter( + &hkdf.v0_ldt_key(), + hkdf.v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()), + [0xFA; 32].into(), + ) + }, + ) + } + + #[test] + fn mangled_de_ciphertext_no_match() { + build_and_deser_with_invalid_decrypter_error( + |mut adv| { + *adv.last_mut().unwrap() ^= 0x01; + adv + }, + build_correct_decrypter, + ) + } + + #[test] + fn mangled_token_ciphertext_no_match() { + build_and_deser_with_invalid_decrypter_error( + |mut adv| { + adv[10] ^= 0x01; + adv + }, + build_correct_decrypter, + ) + } + + #[test] + fn mangled_salt_no_match() { + build_and_deser_with_invalid_decrypter_error( + |mut adv| { + adv[1] ^= 0x01; + adv + }, + build_correct_decrypter, + ) + } + + #[test] + fn extended_ciphertext_no_match() { + build_and_deser_with_invalid_decrypter_error( + |mut adv| { + adv.push(0xEE); + adv + }, + build_correct_decrypter, + ) + } + + fn build_correct_decrypter( + key_seed: &[u8; 32], + identity_token: &V0IdentityToken, + ) -> AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl> { + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed); + ldt_np_adv::build_np_adv_decrypter_from_key_seed( + &hkdf, + hkdf.v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()), + ) + } + + fn build_and_deser_with_invalid_decrypter_error( + alter_adv: impl Fn(Vec<u8>) -> Vec<u8>, + build_decrypter: impl Fn( + &[u8; 32], + &V0IdentityToken, + ) -> AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl>, + ) { + let key_seed = [0; 32]; + let identity_token = V0IdentityToken::from([0x33; V0_IDENTITY_TOKEN_LEN]); + let salt = V0Salt::from([0x01, 0x02]); + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap(); + + let adv = builder.into_advertisement().unwrap(); + let altered_adv = alter_adv(adv.as_slice().to_vec()); + + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + &altered_adv.as_slice()[1..], + ) + .unwrap(); + let ldt = contents.as_ldt().unwrap(); + let decrypter = build_decrypter(&key_seed, &identity_token); + assert_eq!(DecryptError::DecryptOrVerifyError, ldt.try_decrypt(&decrypter).unwrap_err()); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/tests/happy_path.rs b/nearby/presence/np_adv/src/legacy/deserialize/tests/happy_path.rs new file mode 100644 index 0000000..1b07ff9 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/tests/happy_path.rs
@@ -0,0 +1,587 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod unencrypted { + extern crate std; + + use rand::prelude::SliceRandom; + use std::{prelude::rust_2021::*, vec}; + use strum::IntoEnumIterator; + + use crypto_provider_default::CryptoProviderImpl; + + use crate::{ + header::V0Encoding, + legacy::{ + data_elements::{ + actions::{ActionBits, ActionsDataElement, NearbyShare}, + de_type::DataElementType, + tests::test_des::{ + random_test_de, TestDataElement, TestDataElementType, TestDeDeserializer, + }, + tx_power::TxPowerDataElement, + DynamicSerializeDataElement, SerializeDataElement, + }, + deserialize::{ + intermediate::IntermediateAdvContents, DataElementDeserializer, + DeserializedDataElement, StandardDeserializer, + }, + random_data_elements::random_de_plaintext, + serialize::{ + tests::helpers::{LongDataElement, ShortDataElement}, + tests::supports_flavor, + AddDataElementError, AdvBuilder, SerializedAdv, UnencryptedEncoder, + }, + PacketFlavorEnum, Plaintext, BLE_4_ADV_SVC_MAX_CONTENT_LEN, NP_MAX_DE_CONTENT_LEN, + NP_MIN_ADV_CONTENT_LEN, + }, + shared_data::TxPower, + }; + + #[test] + fn parse_min_len_adv() { + // 1 byte + let de = ShortDataElement::new(vec![]); + let mut builder = AdvBuilder::new(UnencryptedEncoder); + builder.add_data_element(de.clone()).unwrap(); + let data = builder.into_advertisement().unwrap(); + // extra byte for version header + assert_eq!(1 + NP_MIN_ADV_CONTENT_LEN, data.len()); + + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &data.as_slice()[1..], + ) + .unwrap(); + let unencrypted = contents.as_unencrypted().unwrap(); + + assert_eq!( + vec![TestDataElement::Short(de)], + unencrypted + .generic_data_elements::<TestDeDeserializer>() + .collect::<Result<Vec<_>, _>>() + .unwrap() + ); + } + + #[test] + fn parse_max_len_adv() { + let de = LongDataElement::new(vec![0x22; NP_MAX_DE_CONTENT_LEN]); + let mut builder = AdvBuilder::new(UnencryptedEncoder); + builder.add_data_element(de.clone()).unwrap(); + let data = builder.into_advertisement().unwrap(); + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, data.len()); + + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &data.as_slice()[1..], + ) + .unwrap(); + let unencrypted = contents.as_unencrypted().unwrap(); + + assert_eq!( + vec![TestDataElement::Long(de)], + unencrypted + .generic_data_elements::<TestDeDeserializer>() + .collect::<Result<Vec<_>, _>>() + .unwrap() + ); + } + + #[test] + fn tx_power() { + let de = TxPowerDataElement::from(TxPower::try_from(7).unwrap()); + let boxed: Box<dyn SerializeDataElement<Plaintext>> = Box::new(de.clone()); + let _ = assert_build_adv_and_deser( + vec![boxed.as_ref().into()], + &[DeserializedDataElement::TxPower(de)], + ); + } + + #[test] + fn actions_min_len() { + let de = ActionsDataElement::from(ActionBits::default()); + + let boxed: Box<dyn SerializeDataElement<Plaintext>> = Box::new(de.clone()); + let data = assert_build_adv_and_deser( + vec![boxed.as_ref().into()], + &[DeserializedDataElement::Actions(de)], + ); + // version, de header, de contents + assert_eq!(3, data.len()); + } + + #[test] + fn typical_tx_power_and_actions() { + let tx = TxPowerDataElement::from(TxPower::try_from(7).unwrap()); + let mut action_bits = ActionBits::default(); + action_bits.set_action(NearbyShare::from(true)); + let actions = ActionsDataElement::from(action_bits); + + let tx_boxed: Box<dyn SerializeDataElement<Plaintext>> = Box::new(tx.clone()); + let actions_boxed: Box<dyn SerializeDataElement<Plaintext>> = Box::new(actions.clone()); + let expected = + vec![DeserializedDataElement::TxPower(tx), DeserializedDataElement::Actions(actions)]; + let adv = assert_build_adv_and_deser( + vec![tx_boxed.as_ref().into(), actions_boxed.as_ref().into()], + &expected, + ); + + let contents = assert_deserialized_contents::<StandardDeserializer>(&expected, &adv); + assert_eq!( + expected, + contents + .as_unencrypted() + .unwrap() + .data_elements() + .collect::<Result<Vec<_>, _>>() + .unwrap() + ); + } + + #[test] + fn random_normal_des_rountrip() { + do_random_roundtrip_test::<StandardDeserializer, _>( + DataElementType::iter() + .filter(|t| supports_flavor(*t, PacketFlavorEnum::Plaintext)) + .collect(), + random_de_plaintext, + |builder, de| match de { + DeserializedDataElement::Actions(a) => builder.add_data_element(a), + DeserializedDataElement::TxPower(tx) => builder.add_data_element(tx), + }, + ) + } + + #[test] + fn random_test_des_rountrip() { + do_random_roundtrip_test::<TestDeDeserializer, _>( + TestDataElementType::iter().collect::<Vec<_>>(), + random_test_de, + |builder, de| match de { + TestDataElement::Short(s) => builder.add_data_element(s), + TestDataElement::Long(l) => builder.add_data_element(l), + }, + ) + } + + fn do_random_roundtrip_test<D, F>( + de_types: Vec<D::DeTypeDisambiguator>, + build_de: F, + add_de: impl Fn( + &mut AdvBuilder<UnencryptedEncoder>, + D::Deserialized<Plaintext>, + ) -> Result<(), AddDataElementError>, + ) where + D: DataElementDeserializer, + F: Fn(D::DeTypeDisambiguator, &mut rand_ext::rand_pcg::Pcg64) -> D::Deserialized<Plaintext>, + { + let mut rng = rand_ext::seeded_rng(); + + for _ in 0..10_000 { + let mut des = Vec::new(); + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + loop { + let de_type = *de_types.choose(&mut rng).unwrap(); + let de = build_de(de_type, &mut rng); + + let add_res = add_de(&mut builder, de.clone()); + + if let Err(e) = add_res { + match e { + AddDataElementError::InsufficientAdvSpace => { + // out of room + break; + } + } + } + + des.push(de); + } + + let serialized = builder.into_advertisement().unwrap(); + assert_deserialized_contents::<D>(&des, &serialized); + } + } + + fn assert_build_adv_and_deser( + des: Vec<DynamicSerializeDataElement<Plaintext>>, + expected: &[DeserializedDataElement<Plaintext>], + ) -> SerializedAdv { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + for de in des { + builder.add_data_element(de).unwrap(); + } + let adv = builder.into_advertisement().unwrap(); + + assert_deserialized_contents::<StandardDeserializer>(expected, &adv); + + adv + } + + fn assert_deserialized_contents<'a, D: DataElementDeserializer>( + expected: &[D::Deserialized<Plaintext>], + adv: &'a SerializedAdv, + ) -> IntermediateAdvContents<'a> { + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &adv.as_slice()[1..], + ) + .unwrap(); + + let unencrypted = contents.as_unencrypted().unwrap(); + assert_eq!( + expected, + unencrypted + .generic_data_elements::<D>() + .collect::<Result<Vec<_>, _>>() + .unwrap() + .as_slice() + ); + contents + } +} + +mod ldt { + use crate::credential::matched::HasIdentityMatch; + use crate::legacy::data_elements::actions::CallTransfer; + use crate::{ + credential::v0::V0BroadcastCredential, + header::V0Encoding, + legacy::{ + data_elements::{ + actions::{ActionBits, ActionsDataElement, NearbyShare}, + de_type::DataElementType, + tests::test_des::{random_test_de, TestDataElementType}, + tests::test_des::{TestDataElement, TestDeDeserializer}, + tx_power::TxPowerDataElement, + DataElementSerializationBuffer, DynamicSerializeDataElement, SerializeDataElement, + }, + deserialize::{ + intermediate::IntermediateAdvContents, DecryptedAdvContents, + DeserializedDataElement, + }, + deserialize::{DataElementDeserializer, StandardDeserializer}, + random_data_elements::random_de_ciphertext, + serialize::{ + tests::helpers::ShortDataElement, tests::supports_flavor, AddDataElementError, + AdvBuilder, LdtEncoder, SerializedAdv, + }, + Ciphertext, PacketFlavorEnum, BLE_4_ADV_SVC_MAX_CONTENT_LEN, NP_MAX_ADV_CONTENT_LEN, + }, + shared_data::TxPower, + }; + use alloc::boxed::Box; + use alloc::vec; + use alloc::vec::Vec; + use crypto_provider_default::CryptoProviderImpl; + use ldt_np_adv::{V0IdentityToken, V0Salt, V0_IDENTITY_TOKEN_LEN}; + use rand::prelude::SliceRandom; + use rand::Rng; + use strum::IntoEnumIterator; + + #[test] + fn parse_min_len() { + // 2 bytes total is the minimum + let de = ShortDataElement::new(vec![7]); + let boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(de.clone()); + let (adv, _decrypted) = build_and_assert_deserialized_matches::<TestDeDeserializer>( + vec![boxed.as_ref().into()], + &[TestDataElement::Short(de)], + ); + + // version and salt + assert_eq!(1 + 2 + ldt_np_adv::VALID_INPUT_LEN.start, adv.len()); + } + + #[test] + fn parse_max_len() { + // 7 bytes total + let de = ShortDataElement::new(vec![1; 6]); + let boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(de.clone()); + let (adv, _decrypted) = build_and_assert_deserialized_matches::<TestDeDeserializer>( + vec![boxed.as_ref().into()], + &[TestDataElement::Short(de)], + ); + + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, adv.len()); + } + + #[test] + fn tx_power() { + let de = TxPowerDataElement::from(TxPower::try_from(3).unwrap()); + let boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(de.clone()); + let _adv = build_and_assert_deserialized_matches::<StandardDeserializer>( + vec![boxed.as_ref().into()], + &[DeserializedDataElement::TxPower(de)], + ); + } + + #[test] + fn actions_min_len() { + let de = ActionsDataElement::from(ActionBits::default()); + let boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(de.clone()); + let (adv, _decrypted) = build_and_assert_deserialized_matches::<StandardDeserializer>( + vec![boxed.as_ref().into()], + &[DeserializedDataElement::Actions(de)], + ); + + // 2 byte actions DE + assert_eq!(1 + 2 + 14 + 2, adv.len()); + } + + #[test] + fn typical_tx_power_and_actions() { + let tx = TxPowerDataElement::from(TxPower::try_from(7).unwrap()); + let mut action_bits = ActionBits::default(); + action_bits.set_action(NearbyShare::from(true)); + action_bits.set_action(CallTransfer::from(true)); + let actions = ActionsDataElement::from(action_bits); + let tx_boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(tx.clone()); + let actions_boxed: Box<dyn SerializeDataElement<Ciphertext>> = Box::new(actions.clone()); + let expected = + [DeserializedDataElement::TxPower(tx), DeserializedDataElement::Actions(actions)]; + let (_adv, decrypted) = build_and_assert_deserialized_matches::<StandardDeserializer>( + vec![tx_boxed.as_ref().into(), actions_boxed.as_ref().into()], + &expected, + ); + assert_eq!( + &expected, + decrypted.data_elements().collect::<Result<Vec<_>, _>>().unwrap().as_slice() + ); + } + + #[test] + fn random_normal_des_roundtrip() { + do_random_roundtrip_test::<StandardDeserializer, _>( + DataElementType::iter() + .filter(|t| supports_flavor(*t, PacketFlavorEnum::Ciphertext)) + .collect(), + random_de_ciphertext, + |builder, de| match de { + DeserializedDataElement::Actions(a) => builder.add_data_element(a), + DeserializedDataElement::TxPower(tx) => builder.add_data_element(tx), + }, + |de| match de { + DeserializedDataElement::Actions(a) => serialized_len(a), + DeserializedDataElement::TxPower(tx) => serialized_len(tx), + }, + ) + } + + #[test] + fn random_test_des_roundtrip() { + do_random_roundtrip_test::<TestDeDeserializer, _>( + TestDataElementType::iter().collect(), + random_test_de, + |builder, de| builder.add_data_element(de), + serialized_len, + ) + } + + fn do_random_roundtrip_test<D, F>( + de_types: Vec<D::DeTypeDisambiguator>, + build_de: F, + add_de: impl Fn( + &mut AdvBuilder<LdtEncoder<CryptoProviderImpl>>, + D::Deserialized<Ciphertext>, + ) -> Result<(), AddDataElementError>, + serialized_len: impl Fn(&D::Deserialized<Ciphertext>) -> usize, + ) where + D: DataElementDeserializer, + F: Fn( + D::DeTypeDisambiguator, + &mut rand_ext::rand_pcg::Pcg64, + ) -> D::Deserialized<Ciphertext>, + { + let mut rng = rand_ext::seeded_rng(); + + for _ in 0..10_000 { + let mut added_des = Vec::new(); + let mut current_len = 0; + + let key_seed: [u8; 32] = rng.gen(); + let salt: ldt_np_adv::V0Salt = rng.gen::<[u8; 2]>().into(); + let identity_token = V0IdentityToken::from(rng.gen::<[u8; V0_IDENTITY_TOKEN_LEN]>()); + + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + loop { + let de_type = *de_types.choose(&mut rng).unwrap(); + let de = build_de(de_type, &mut rng); + + if let Err(e) = add_de(&mut builder, de.clone()) { + match e { + AddDataElementError::InsufficientAdvSpace => { + if current_len + < ldt_np_adv::VALID_INPUT_LEN.start - V0_IDENTITY_TOKEN_LEN + { + // keep trying, not enough for LDT + continue; + } + // out of room + break; + } + } + } + + current_len += serialized_len(&de); + added_des.push(de); + } + + let adv = builder.into_advertisement().unwrap(); + assert_deserialized_contents::<D>(&key_seed, identity_token, salt, &adv, &added_des); + } + } + + fn build_and_assert_deserialized_matches<D: DataElementDeserializer>( + des: Vec<DynamicSerializeDataElement<Ciphertext>>, + expected: &[D::Deserialized<Ciphertext>], + ) -> (SerializedAdv, DecryptedAdvContents) { + let key_seed = [0; 32]; + let identity_token = V0IdentityToken::from([0x33; V0_IDENTITY_TOKEN_LEN]); + let salt = V0Salt::from([0x01, 0x02]); + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + for de in des { + builder.add_data_element(de).unwrap(); + } + let adv = builder.into_advertisement().unwrap(); + + let decrypted = + assert_deserialized_contents::<D>(&key_seed, identity_token, salt, &adv, expected); + (adv, decrypted) + } + + fn assert_deserialized_contents<D: DataElementDeserializer>( + key_seed: &[u8; 32], + identity_token: V0IdentityToken, + salt: V0Salt, + adv: &SerializedAdv, + expected: &[D::Deserialized<Ciphertext>], + ) -> DecryptedAdvContents { + let contents = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + &adv.as_slice()[1..], + ) + .unwrap(); + let ldt = contents.as_ldt().unwrap(); + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(key_seed); + let identity_token_hmac: [u8; 32] = hkdf + .v0_identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.as_slice()); + let decrypter = + ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, identity_token_hmac); + let decrypted = ldt.try_decrypt(&decrypter).unwrap(); + + assert_eq!(salt, decrypted.salt()); + assert_eq!(identity_token, decrypted.identity_token()); + + assert_eq!( + expected, + decrypted.generic_data_elements::<D>().collect::<Result<Vec<_>, _>>().unwrap() + ); + + decrypted + } + + /// serialized length including header + fn serialized_len<S: SerializeDataElement<Ciphertext>>(de: &S) -> usize { + let mut buf = DataElementSerializationBuffer::new(NP_MAX_ADV_CONTENT_LEN).unwrap(); + de.serialize_contents(&mut buf).unwrap(); + buf.len() + 1 + } +} + +mod coverage_gaming { + use alloc::format; + + use crypto_provider_default::CryptoProviderImpl; + + use crate::header::V0Encoding; + use crate::legacy::data_elements::de_type::DataElementType; + use crate::legacy::deserialize::intermediate::{IntermediateAdvContents, LdtAdvContents}; + use crate::legacy::deserialize::{ + AdvDeserializeError, DeIterator, RawDataElement, StandardDeserializer, + }; + use crate::legacy::Plaintext; + + #[test] + fn iac_debug_eq_test_helpers() { + let iac = IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &[0xFF], + ) + .unwrap(); + let _ = format!("{:?}", iac); + assert_eq!(iac, iac); + } + + #[test] + fn iac_test_helpers() { + assert_eq!( + None, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Unencrypted, + &[0xFF], + ) + .unwrap() + .as_ldt() + ); + assert_eq!( + None, + IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + &[0xFF; 18], + ) + .unwrap() + .as_unencrypted() + ); + } + + #[test] + fn ade_debug_clone() { + let _ = format!("{:?}", AdvDeserializeError::NoDataElements.clone()); + } + + #[test] + fn rde_debug_eq() { + let rde = RawDataElement::<'_, StandardDeserializer> { + de_type: DataElementType::Actions, + contents: &[], + }; + + let _ = format!("{:?}", rde); + assert_eq!(rde, rde); + } + + #[test] + fn de_iterator_debug_clone_eq() { + let i = DeIterator::<'_, Plaintext>::new(&[]); + let _ = format!("{:?}", i.clone()); + assert_eq!(i, i); + } + + #[test] + fn ldt_adv_contents_debug() { + let lac = LdtAdvContents::new::<CryptoProviderImpl>([0; 2].into(), &[0; 16]).unwrap(); + let _ = format!("{:?}", lac); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/deserialize/tests/mod.rs b/nearby/presence/np_adv/src/legacy/deserialize/tests/mod.rs new file mode 100644 index 0000000..0a016e1 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/deserialize/tests/mod.rs
@@ -0,0 +1,194 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(unused_results, clippy::unwrap_used)] + +extern crate std; + +use super::*; +use crate::header::V0Encoding; +use crate::legacy::deserialize::intermediate::{IntermediateAdvContents, LdtAdvContents}; +use crate::{ + credential::v0::V0BroadcastCredential, + legacy::{ + serialize::{AdvBuilder, LdtEncoder}, + BLE_4_ADV_SVC_MAX_CONTENT_LEN, + }, + shared_data::TxPower, +}; +use crypto_provider::CryptoProvider; +use crypto_provider_default::CryptoProviderImpl; +use ldt_np_adv::V0_IDENTITY_TOKEN_LEN; + +mod error_conditions; +mod happy_path; + +#[test] +fn decrypt_with_wrong_key_seed_error() { + let salt = ldt_np_adv::V0Salt::from([0x22; 2]); + let metadata_key: [u8; V0_IDENTITY_TOKEN_LEN] = [0x33; V0_IDENTITY_TOKEN_LEN]; + let correct_key_seed = [0x11_u8; 32]; + + let (adv_content, correct_cipher) = + build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); + let eac = parse_ciphertext_adv_contents(&correct_cipher, &adv_content.as_slice()[1..]); + + // wrong key seed doesn't work (derives wrong ldt key, wrong hmac key) + let wrong_key_seed_cipher = { + let key_seed = [0x22_u8; 32]; + + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let metadata_key_hmac: [u8; 32] = + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&metadata_key); + ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac) + }; + + assert_eq!( + DecryptError::DecryptOrVerifyError, + eac.try_decrypt(&wrong_key_seed_cipher).unwrap_err() + ); +} + +#[test] +fn decrypt_with_wrong_hmac_key_error() { + let salt = ldt_np_adv::V0Salt::from([0x22; 2]); + let metadata_key: [u8; V0_IDENTITY_TOKEN_LEN] = [0x33; V0_IDENTITY_TOKEN_LEN]; + let correct_key_seed = [0x11_u8; 32]; + + let (adv_content, correct_cipher_config) = + build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); + let eac = parse_ciphertext_adv_contents(&correct_cipher_config, &adv_content.as_slice()[1..]); + + let wrong_hmac_key_cipher = { + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&[0x10_u8; 32]); + let metadata_key_hmac: [u8; 32] = + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&metadata_key); + + ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac) + }; + + assert_eq!( + DecryptError::DecryptOrVerifyError, + eac.try_decrypt::<CryptoProviderImpl>(&wrong_hmac_key_cipher).unwrap_err() + ); +} + +#[test] +fn decrypt_with_wrong_hmac_error() { + let salt = ldt_np_adv::V0Salt::from([0x22; 2]); + let metadata_key: [u8; V0_IDENTITY_TOKEN_LEN] = [0x33; V0_IDENTITY_TOKEN_LEN]; + let correct_key_seed = [0x11_u8; 32]; + + let (adv_content, correct_cipher_config) = + build_ciphertext_adv_contents(salt, &metadata_key, correct_key_seed); + let eac = parse_ciphertext_adv_contents(&correct_cipher_config, &adv_content.as_slice()[1..]); + + let wrong_hmac_key_cipher = { + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&correct_key_seed); + + ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, [0x77; 32]) + }; + + assert_eq!( + DecryptError::DecryptOrVerifyError, + eac.try_decrypt(&wrong_hmac_key_cipher).unwrap_err() + ); +} + +fn build_ciphertext_adv_contents<C: CryptoProvider>( + salt: ldt_np_adv::V0Salt, + metadata_key: &[u8; 14], + correct_key_seed: [u8; 32], +) -> ( + ArrayView<u8, { BLE_4_ADV_SVC_MAX_CONTENT_LEN }>, + ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C>, +) { + let hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&correct_key_seed); + + let metadata_key_hmac: [u8; 32] = + hkdf.v0_identity_token_hmac_key().calculate_hmac::<C>(metadata_key.as_slice()); + + let correct_cipher = ldt_np_adv::build_np_adv_decrypter_from_key_seed(&hkdf, metadata_key_hmac); + + let broadcast_cred = + V0BroadcastCredential::new(correct_key_seed, V0IdentityToken::from(*metadata_key)); + + let mut builder = AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); + (builder.into_advertisement().unwrap(), correct_cipher) +} + +fn parse_ciphertext_adv_contents<'b>( + cipher: &ldt_np_adv::AuthenticatedNpLdtDecryptCipher<CryptoProviderImpl>, + adv_content: &'b [u8], +) -> LdtAdvContents<'b> { + let eac = match IntermediateAdvContents::deserialize::<CryptoProviderImpl>( + V0Encoding::Ldt, + adv_content, + ) + .unwrap() + { + IntermediateAdvContents::Unencrypted(_) => panic!(), + // quick confirmation that we did get something + IntermediateAdvContents::Ldt(eac) => eac, + }; + + // correct cipher works + assert!(eac.try_decrypt(cipher).is_ok()); + + eac +} + +mod coverage_gaming { + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement}; + use crate::legacy::deserialize::{ + DecryptError, DecryptedAdvContents, DeserializedDataElement, StandardDeserializer, + }; + use crate::legacy::Plaintext; + use alloc::format; + use array_view::ArrayView; + use ldt_np_adv::{V0_IDENTITY_TOKEN_LEN, V0_SALT_LEN}; + + #[test] + fn decrypt_error_debug_clone() { + let _ = format!("{:?}", DecryptError::DecryptOrVerifyError.clone()); + } + + #[test] + fn deserialized_data_element_debug() { + let _ = format!( + "{:?}", + DeserializedDataElement::<Plaintext>::Actions(ActionsDataElement::from( + ActionBits::default() + )) + ); + } + + #[test] + fn decrypted_adv_contents_debug_partial_eq() { + let dac = DecryptedAdvContents::new( + [0; V0_IDENTITY_TOKEN_LEN].into(), + [0; V0_SALT_LEN].into(), + ArrayView::try_from_slice(&[]).unwrap(), + ); + let _ = format!("{:?}", dac); + assert_eq!(dac, dac) + } + + #[test] + fn standard_deserializer_debug_eq_clone() { + assert_eq!(StandardDeserializer, StandardDeserializer); + let _ = format!("{:?}", StandardDeserializer.clone()); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/mod.rs b/nearby/presence/np_adv/src/legacy/mod.rs index 59f2308..2bac636 100644 --- a/nearby/presence/np_adv/src/legacy/mod.rs +++ b/nearby/presence/np_adv/src/legacy/mod.rs
@@ -14,14 +14,20 @@ //! V0 advertisement support. -use crate::MetadataKey; +use crate::credential::matched::{MatchedCredential, WithMatchedCredential}; +use crate::legacy::deserialize::intermediate::{IntermediateAdvContents, UnencryptedAdvContents}; +use crate::{ + credential::{ + book::CredentialBook, v0::V0DiscoveryCryptoMaterial, DiscoveryMetadataCryptoMaterial, + }, + header::V0Encoding, + legacy::deserialize::{DecryptError, DecryptedAdvContents}, + AdvDeserializationError, +}; use core::fmt; use crypto_provider::CryptoProvider; -use ldt_np_adv::NP_LEGACY_METADATA_KEY_LEN; -pub mod actions; pub mod data_elements; -pub mod de_type; pub mod deserialize; pub mod serialize; @@ -30,34 +36,19 @@ /// Advertisement capacity after 5 bytes of BLE header and 2 bytes of svc UUID are reserved from a /// 31-byte advertisement -pub const BLE_ADV_SVC_CONTENT_LEN: usize = 24; -/// Maximum possible DE content: packet size minus 2 for adv header & DE header -const NP_MAX_DE_CONTENT_LEN: usize = BLE_ADV_SVC_CONTENT_LEN - 2; - -/// "Short" 14-byte metadata key type employed for V0, which needs to be -/// expanded to a regular-size 16-byte metadata key to decrypt metadata. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -pub struct ShortMetadataKey(pub [u8; NP_LEGACY_METADATA_KEY_LEN]); - -impl AsRef<[u8]> for ShortMetadataKey { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl ShortMetadataKey { - /// Expand this short 14-byte metadata key to a 16-byte metadata key - /// which may be used to decrypt metadata. - pub fn expand<C: CryptoProvider>(&self) -> MetadataKey { - let expanded_bytes = np_hkdf::legacy_metadata_expanded_key::<C>(&self.0); - MetadataKey(expanded_bytes) - } -} +pub const BLE_4_ADV_SVC_MAX_CONTENT_LEN: usize = 24; +/// Maximum possible advertisement NP-level content: packet size minus 1 for version header +const NP_MAX_ADV_CONTENT_LEN: usize = BLE_4_ADV_SVC_MAX_CONTENT_LEN - 1; +/// Minimum advertisement NP-level content. +/// Only meaningful for unencrypted advertisements, as LDT advertisements already have salt, token, etc. +const NP_MIN_ADV_CONTENT_LEN: usize = 1; +/// Max length of an individual DE's content +pub(crate) const NP_MAX_DE_CONTENT_LEN: usize = NP_MAX_ADV_CONTENT_LEN - 1; /// Marker type to allow disambiguating between plaintext and encrypted packets at compile time. /// /// See also [PacketFlavorEnum] for when runtime flavor checks are more suitable. -pub trait PacketFlavor: fmt::Debug + Clone + Copy { +pub trait PacketFlavor: fmt::Debug + Clone + Copy + PartialEq + Eq { /// The corresponding [PacketFlavorEnum] variant. const ENUM_VARIANT: PacketFlavorEnum; } @@ -80,10 +71,90 @@ /// An enum version of the implementors of [PacketFlavor] for use cases where runtime checking is /// a better fit than compile time checking. -#[derive(Debug, Clone, Copy, strum_macros::EnumIter, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PacketFlavorEnum { /// Corresponds to [Plaintext]. Plaintext, /// Corresponds to [Ciphertext]. Ciphertext, } + +/// Deserialize and decrypt the contents of a v0 adv after the version header +pub(crate) fn deser_decrypt_v0<'adv, 'cred, B, P>( + encoding: V0Encoding, + cred_book: &'cred B, + remaining: &'adv [u8], +) -> Result<V0AdvertisementContents<'adv, B::Matched>, AdvDeserializationError> +where + B: CredentialBook<'cred>, + P: CryptoProvider, +{ + match IntermediateAdvContents::deserialize::<P>(encoding, remaining)? { + IntermediateAdvContents::Unencrypted(p) => Ok(V0AdvertisementContents::Plaintext(p)), + IntermediateAdvContents::Ldt(c) => { + for (crypto_material, matched) in cred_book.v0_iter() { + let ldt = crypto_material.ldt_adv_cipher::<P>(); + match c.try_decrypt(&ldt) { + Ok(c) => { + let metadata_nonce = crypto_material.metadata_nonce::<P>(); + return Ok(V0AdvertisementContents::Decrypted(WithMatchedCredential::new( + matched, + metadata_nonce, + c, + ))); + } + Err(e) => match e { + DecryptError::DecryptOrVerifyError => continue, + }, + } + } + Ok(V0AdvertisementContents::NoMatchingCredentials) + } + } +} + +/// Advertisement content that was either already plaintext or has been decrypted. +#[derive(Debug, PartialEq, Eq)] +pub enum V0AdvertisementContents<'adv, M: MatchedCredential> { + /// Contents of a plaintext advertisement + Plaintext(UnencryptedAdvContents<'adv>), + /// Contents that was ciphertext in the original advertisement, and has been decrypted + /// with the credential in the [MatchedCredential] + Decrypted(WithMatchedCredential<M, DecryptedAdvContents>), + /// The advertisement was encrypted, but no credentials matched + NoMatchingCredentials, +} + +#[cfg(test)] +mod tests { + mod coverage_gaming { + use crate::legacy::{Ciphertext, PacketFlavorEnum, Plaintext}; + + extern crate std; + + use std::format; + + #[test] + fn plaintext_flavor() { + // debug + let _ = format!("{:?}", Plaintext); + // eq and clone + assert_eq!(Plaintext, Plaintext.clone()) + } + + #[test] + fn ciphertext_flavor() { + // debug + let _ = format!("{:?}", Ciphertext); + // eq and clone + assert_eq!(Ciphertext, Ciphertext.clone()) + } + + #[allow(clippy::clone_on_copy)] + #[test] + fn flavor_enum() { + // clone + let _ = PacketFlavorEnum::Plaintext.clone(); + } + } +}
diff --git a/nearby/presence/np_adv/src/legacy/random_data_elements.rs b/nearby/presence/np_adv/src/legacy/random_data_elements.rs index aca906b..e3fbde1 100644 --- a/nearby/presence/np_adv/src/legacy/random_data_elements.rs +++ b/nearby/presence/np_adv/src/legacy/random_data_elements.rs
@@ -16,18 +16,18 @@ extern crate std; +use crate::legacy::data_elements::actions::tests::{ + set_ciphertexttext_action, set_plaintext_action, +}; use crate::{ legacy::{ - actions::*, - data_elements::*, - de_type::PlainDataElementType, - deserialize::PlainDataElement, - serialize::{DataElementBundle, ToDataElementBundle}, + data_elements::{actions::*, de_type::DataElementType, tx_power::TxPowerDataElement, *}, + deserialize::DeserializedDataElement, Ciphertext, PacketFlavor, PacketFlavorEnum, Plaintext, }, - shared_data::{ContextSyncSeqNum, TxPower}, + shared_data::TxPower, }; -use rand_ext::rand::{self, distributions, prelude::SliceRandom as _}; +use rand_ext::rand::{distributions, prelude::SliceRandom as _}; use std::prelude::rust_2021::*; use strum::IntoEnumIterator; @@ -45,25 +45,16 @@ let mut bits = ActionBits::default(); for a in selected_actions { - match a { - ActionType::ContextSyncSeqNum => { - bits.set_action(ContextSyncSeqNum::try_from(rng.gen_range(0..=15)).unwrap()) - } - // generating boolean actions with `true` since we already did our random selection - // of which actions to use above - ActionType::NearbyShare => bits.set_action(NearbyShare::from(true)), - ActionType::Finder => bits.set_action(Finder::from(true)), - ActionType::FastPairSass => bits.set_action(FastPairSass::from(true)), - ActionType::ActiveUnlock - | ActionType::PresenceManager - | ActionType::InstantTethering - | ActionType::PhoneHub => unreachable!("not plaintext actions"), - } + // generating boolean actions with `true` since we already did our random selection + // of which actions to use above + + set_plaintext_action(*a, true, &mut bits); } ActionsDataElement::from(bits) } } + impl distributions::Distribution<ActionsDataElement<Ciphertext>> for distributions::Standard { fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ActionsDataElement<Ciphertext> { let mut available_actions = ActionType::iter() @@ -78,20 +69,9 @@ let mut bits = ActionBits::default(); for a in selected_actions { - match a { - ActionType::ContextSyncSeqNum => { - bits.set_action(ContextSyncSeqNum::try_from(rng.gen_range(0..=15)).unwrap()) - } - ActionType::ActiveUnlock => bits.set_action(ActiveUnlock::from(true)), - // generating boolean actions with `true` since we already did our random selection - // of which actions to use above - ActionType::NearbyShare => bits.set_action(NearbyShare::from(true)), - ActionType::PresenceManager => bits.set_action(PresenceManager::from(true)), - ActionType::InstantTethering => bits.set_action(InstantTethering::from(true)), - ActionType::PhoneHub => bits.set_action(PhoneHub::from(true)), - ActionType::Finder => bits.set_action(Finder::from(true)), - ActionType::FastPairSass => bits.set_action(FastPairSass::from(true)), - } + // generating boolean actions with `true` since we already did our random selection + // of which actions to use above + set_ciphertexttext_action(*a, true, &mut bits); } ActionsDataElement::from(bits) @@ -112,60 +92,45 @@ } } -/// Generate a random instance of the requested DE and return it wrapped in [PlainDataElement] along -/// with its bundle representation. -pub(crate) fn rand_de_and_bundle<F, D, E, R>( - to_enum: E, - rng: &mut R, -) -> (PlainDataElement<F>, DataElementBundle<F>) +/// Generate a random instance of the requested DE and return it wrapped in [DeserializedDataElement]. +pub(crate) fn rand_de<F, D, E, R>(to_enum: E, rng: &mut R) -> DeserializedDataElement<F> where F: PacketFlavor, - D: ToDataElementBundle<F>, - E: Fn(D) -> PlainDataElement<F>, + D: SerializeDataElement<F>, + E: Fn(D) -> DeserializedDataElement<F>, R: rand::Rng, distributions::Standard: distributions::Distribution<D>, { let de = rng.gen::<D>(); - let bundle = de.to_de_bundle(); - (to_enum(de), bundle) + to_enum(de) } /// Generate a random instance of the requested de type, or `None` if that type does not support /// plaintext. pub(crate) fn random_de_plaintext<R>( - de_type: PlainDataElementType, + de_type: DataElementType, rng: &mut R, -) -> Option<(PlainDataElement<Plaintext>, DataElementBundle<Plaintext>)> +) -> DeserializedDataElement<Plaintext> where R: rand::Rng, { - let opt = match de_type { - PlainDataElementType::TxPower => Some(rand_de_and_bundle(PlainDataElement::TxPower, rng)), - PlainDataElementType::Actions => Some(rand_de_and_bundle(PlainDataElement::Actions, rng)), - }; - - // make sure flavor support is consistent - assert_eq!(opt.is_some(), de_type.supports_flavor(PacketFlavorEnum::Plaintext)); - - opt + match de_type { + DataElementType::TxPower => rand_de(DeserializedDataElement::TxPower, rng), + DataElementType::Actions => rand_de(DeserializedDataElement::Actions, rng), + } } /// Generate a random instance of the requested de type, or `None` if that type does not support /// ciphertext. pub(crate) fn random_de_ciphertext<R>( - de_type: PlainDataElementType, + de_type: DataElementType, rng: &mut R, -) -> Option<(PlainDataElement<Ciphertext>, DataElementBundle<Ciphertext>)> +) -> DeserializedDataElement<Ciphertext> where R: rand::Rng, { - let opt = match de_type { - PlainDataElementType::TxPower => Some(rand_de_and_bundle(PlainDataElement::TxPower, rng)), - PlainDataElementType::Actions => Some(rand_de_and_bundle(PlainDataElement::Actions, rng)), - }; - - // make sure flavor support is consistent - assert_eq!(opt.is_some(), de_type.supports_flavor(PacketFlavorEnum::Ciphertext)); - - opt + match de_type { + DataElementType::TxPower => rand_de(DeserializedDataElement::TxPower, rng), + DataElementType::Actions => rand_de(DeserializedDataElement::Actions, rng), + } }
diff --git a/nearby/presence/np_adv/src/legacy/serialize/header.rs b/nearby/presence/np_adv/src/legacy/serialize/header.rs new file mode 100644 index 0000000..7859633 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/serialize/header.rs
@@ -0,0 +1,74 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use ldt_np_adv::{V0IdentityToken, V0Salt}; + +/// Format || salt || token +const ADV_HEADER_MAX_LEN: usize = 1 + 2 + 14; + +/// Serializes a V0 header. +/// +/// Does not include the overall NP version header byte that defines the adv +/// version. +pub struct V0Header { + header_bytes: tinyvec::ArrayVec<[u8; ADV_HEADER_MAX_LEN]>, +} + +impl V0Header { + pub(crate) fn unencrypted() -> Self { + let header_bytes = tinyvec::ArrayVec::new(); + Self { header_bytes } + } + + pub(crate) fn ldt_short_salt(salt: V0Salt, identity_token: V0IdentityToken) -> Self { + let mut header_bytes = tinyvec::ArrayVec::new(); + header_bytes.extend_from_slice(salt.bytes().as_slice()); + header_bytes.extend_from_slice(identity_token.as_slice()); + Self { header_bytes } + } + + /// The returned slice must be shorter than [crate::legacy::BLE_4_ADV_SVC_MAX_CONTENT_LEN] - 1. + pub(crate) fn as_slice(&self) -> &[u8] { + self.header_bytes.as_slice() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ldt_np_adv::{V0_IDENTITY_TOKEN_LEN, V0_SALT_LEN}; + + const SHORT_SALT_BYTES: [u8; V0_SALT_LEN] = [0x10, 0x11]; + const TOKEN_BYTES: [u8; V0_IDENTITY_TOKEN_LEN] = + [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D]; + + #[test] + fn unencrypted_slice() { + assert_eq!(&[0_u8; 0], V0Header::unencrypted().as_slice()); + } + + #[rustfmt::skip] + #[test] + fn ldt_short_salt_slice() { + assert_eq!( + &[ + // salt + 0x10, 0x11, + // token + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D + ], + V0Header::ldt_short_salt(SHORT_SALT_BYTES.into(), TOKEN_BYTES.into()).as_slice() + ); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/serialize/mod.rs b/nearby/presence/np_adv/src/legacy/serialize/mod.rs index 3746796..1906fb2 100644 --- a/nearby/presence/np_adv/src/legacy/serialize/mod.rs +++ b/nearby/presence/np_adv/src/legacy/serialize/mod.rs
@@ -19,10 +19,9 @@ //! Serializing a plaintext advertisement: //! //! ``` -//! use np_adv::{legacy::{data_elements::*, serialize::*}, shared_data::*, PublicIdentity}; -//! use np_adv::shared_data::TxPower; +//! use np_adv::{legacy::{data_elements::tx_power::TxPowerDataElement, serialize::*}, shared_data::*}; //! -//! let mut builder = AdvBuilder::new(PublicIdentity::default()); +//! let mut builder = AdvBuilder::new(UnencryptedEncoder); //! builder //! .add_data_element(TxPowerDataElement::from(TxPower::try_from(3).expect("3 is a valid TxPower value"))) //! .unwrap(); @@ -30,7 +29,6 @@ //! assert_eq!( //! &[ //! 0x00, // Adv Header -//! 0x03, // Public DE header //! 0x15, 0x03, // tx power de //! ], //! packet.as_slice() @@ -40,29 +38,25 @@ //! Serializing an encrypted advertisement: //! //! ``` -//! use np_adv::{shared_data::*, de_type::*, legacy::{de_type::*, data_elements::*, serialize::*, *}}; -//! use np_adv::credential::{v0::V0, SimpleBroadcastCryptoMaterial}; +//! use np_adv::{shared_data::*, legacy::{data_elements::de_type::*, data_elements::tx_power::TxPowerDataElement, serialize::*, *}}; +//! use np_adv::credential::{v0::{V0, V0BroadcastCredential}}; //! use crypto_provider::CryptoProvider; //! use crypto_provider_default::CryptoProviderImpl; -//! use ldt_np_adv::{salt_padder, LegacySalt, LdtEncrypterXtsAes128}; +//! use ldt_np_adv::{V0Salt, V0IdentityToken}; //! //! // Generate these from proper CSPRNGs -- using fixed data here -//! let metadata_key = ShortMetadataKey([0x33; 14]); -//! let salt = LegacySalt::from([0x01, 0x02]); +//! let metadata_key = V0IdentityToken::from([0x33; 14]); +//! let salt = V0Salt::from([0x01, 0x02]); //! let key_seed = [0x44; 32]; -//! let ldt_enc = LdtEncrypterXtsAes128::<CryptoProviderImpl>::new( -//! &np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed).legacy_ldt_key() -//! ); //! -//! let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new( +//! let broadcast_cred = V0BroadcastCredential::new( //! key_seed, //! metadata_key, //! ); //! -//! let mut builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( -//! EncryptedIdentityDataElementType::Private, +//! let mut builder = AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new( //! salt, -//! &broadcast_cm, +//! &broadcast_cred, //! )); //! //! builder @@ -71,195 +65,218 @@ //! //! let packet = builder.into_advertisement().unwrap(); //! ``` -use crate::credential::{v0::V0, BroadcastCryptoMaterial}; -use crate::{ - de_type::{EncryptedIdentityDataElementType, IdentityDataElementType}, - legacy::{ - de_type::{DataElementType, DeActualLength, DeEncodedLength, PlainDataElementType}, - Ciphertext, PacketFlavor, Plaintext, ShortMetadataKey, BLE_ADV_SVC_CONTENT_LEN, - NP_MAX_DE_CONTENT_LEN, - }, - DeLengthOutOfRange, PublicIdentity, -}; +use core::fmt; + use array_view::ArrayView; -use core::{convert, fmt, marker}; use crypto_provider::CryptoProvider; +use ldt::LdtCipher; +use ldt_np_adv::{V0IdentityToken, V0_IDENTITY_TOKEN_LEN}; +use sink::Sink; + +use crate::credential::v0::V0BroadcastCredential; +use crate::{ + extended::to_array_view, + header::{VERSION_HEADER_V0_LDT, VERSION_HEADER_V0_UNENCRYPTED}, + legacy::{ + data_elements::{ + de_type::{DeActualLength, DeEncodedLength, DeTypeCode}, + DataElementSerializationBuffer, DataElementSerializeError, SerializeDataElement, + }, + Ciphertext, PacketFlavor, Plaintext, BLE_4_ADV_SVC_MAX_CONTENT_LEN, NP_MAX_ADV_CONTENT_LEN, + NP_MIN_ADV_CONTENT_LEN, + }, +}; + +mod header; #[cfg(test)] -mod tests; +pub(crate) mod tests; -/// An identity used in serializing an advertisement. -pub trait Identity: fmt::Debug { +/// An encoder used in serializing an advertisement. +pub trait AdvEncoder: fmt::Debug { /// The flavor of packet this identity produces type Flavor: PacketFlavor; /// The error returned if postprocessing fails type Error: fmt::Debug; - /// How much space needs to be reserved for this identity's prefix bytes - const OVERHEAD_LEN: usize; + + /// The version header to put at the start of the advertisement. + const VERSION_HEADER: u8; + + /// The V0-specific header to be written at the start of the advertisement + /// immediately after the version header. + fn header(&self) -> header::V0Header; /// Perform identity-specific manipulation to the serialized DEs to produce the final /// advertisement format. /// - /// `buf` is `OVERHEAD_LEN` bytes set aside for the identity's use, followed by all of the DEs - /// added to a packet. It does not include the NP top level header. + /// `buf` has the contents of [Self::header] written at the start, followed + /// by all of the DEs added to a packet. It does not include the NP top level header. + /// + /// The first `header_len` bytes of `buf` are the bytes produced by the call to [Self::header]. /// /// Returns `Ok` if postprocessing was successful and the packet is finished, or `Err` if /// postprocessing failed and the packet should be discarded. - fn postprocess(&self, buf: &mut [u8]) -> Result<(), Self::Error>; + fn postprocess(&self, header_len: usize, buf: &mut [u8]) -> Result<(), Self::Error>; } -lazy_static::lazy_static! { - // Avoid either a panic-able code path or an error case that never happens by precalculating. - static ref PUBLIC_IDENTITY_DE_HEADER: u8 = - encode_de_header_actual_len(DataElementType::PublicIdentity, DeActualLength::ZERO).expect("de length is in range"); -} +/// An unencrypted encoder with no associated identity. +#[derive(Debug)] +pub struct UnencryptedEncoder; -impl Identity for PublicIdentity { +impl AdvEncoder for UnencryptedEncoder { type Flavor = Plaintext; - type Error = convert::Infallible; - // 1 byte for public DE header (0 content) - const OVERHEAD_LEN: usize = 1; + type Error = UnencryptedEncodeError; + const VERSION_HEADER: u8 = VERSION_HEADER_V0_UNENCRYPTED; - fn postprocess(&self, buf: &mut [u8]) -> Result<(), Self::Error> { - buf[0] = *PUBLIC_IDENTITY_DE_HEADER; + fn header(&self) -> header::V0Header { + header::V0Header::unencrypted() + } - Ok(()) + fn postprocess(&self, _header_len: usize, buf: &mut [u8]) -> Result<(), Self::Error> { + if buf.len() < NP_MIN_ADV_CONTENT_LEN { + Err(UnencryptedEncodeError::InvalidLength) + } else { + Ok(()) + } } } -/// Identity used for encrypted packets (private, trusted, provisioned) that encrypts other DEs +/// Unencrypted encoding errors +#[derive(Debug, PartialEq, Eq)] +pub enum UnencryptedEncodeError { + /// The advertisement content was outside the valid range + InvalidLength, +} + +/// Encoder used for encrypted packets (private, trusted, provisioned) that encrypts other DEs /// (as well as the metadata key). -pub struct LdtIdentity<C: CryptoProvider> { - de_type: EncryptedIdentityDataElementType, - salt: ldt_np_adv::LegacySalt, - metadata_key: ShortMetadataKey, - ldt_enc: ldt_np_adv::LdtEncrypterXtsAes128<C>, +pub struct LdtEncoder<C: CryptoProvider> { + salt: ldt_np_adv::V0Salt, + identity_token: V0IdentityToken, + ldt_enc: ldt_np_adv::NpLdtEncryptCipher<C>, } // Exclude sensitive members -impl<C: CryptoProvider> fmt::Debug for LdtIdentity<C> { +impl<C: CryptoProvider> fmt::Debug for LdtEncoder<C> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "LdtIdentity {{ de_type: {:?}, salt: {:X?} }}", self.de_type, self.salt) + write!(f, "LdtEncoder {{ salt: {:X?} }}", self.salt) } } -impl<C: CryptoProvider> LdtIdentity<C> { +impl<C: CryptoProvider> LdtEncoder<C> { /// Build an `LdtIdentity` for the provided identity type, salt, and /// broadcast crypto-materials. - pub fn new<B: BroadcastCryptoMaterial<V0>>( - de_type: EncryptedIdentityDataElementType, - salt: ldt_np_adv::LegacySalt, - crypto_material: &B, - ) -> Self { - let metadata_key = crypto_material.metadata_key(); - let key_seed = crypto_material.key_seed(); + pub fn new(salt: ldt_np_adv::V0Salt, broadcast_cred: &V0BroadcastCredential) -> Self { + let identity_token = broadcast_cred.identity_token(); + let key_seed = broadcast_cred.key_seed(); let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed); - let ldt_key = key_seed_hkdf.legacy_ldt_key(); - let ldt_enc = ldt_np_adv::LdtEncrypterXtsAes128::<C>::new(&ldt_key); + let ldt_key = key_seed_hkdf.v0_ldt_key(); + let ldt_enc = ldt_np_adv::NpLdtEncryptCipher::<C>::new(&ldt_key); - Self { de_type, salt, metadata_key, ldt_enc } + Self { salt, identity_token, ldt_enc } } } -impl<C: CryptoProvider> Identity for LdtIdentity<C> { +impl<C: CryptoProvider> AdvEncoder for LdtEncoder<C> { type Flavor = Ciphertext; - type Error = LdtPostprocessError; - // Identity DE header + salt + metadata key - const OVERHEAD_LEN: usize = 17; + type Error = LdtEncodeError; + const VERSION_HEADER: u8 = VERSION_HEADER_V0_LDT; - fn postprocess(&self, buf: &mut [u8]) -> Result<(), LdtPostprocessError> { - let de_type = self.de_type.as_identity_data_element_type(); - // there's space for the identity DE header byte, but we don't count that in the DE length - let actual_len: DeActualLength = buf - .len() - .checked_sub(1) - .ok_or(LdtPostprocessError::InvalidLength) - .and_then(|len| len.try_into().map_err(|_e| LdtPostprocessError::InvalidLength))?; - // header - buf[0] = encode_de_header_actual_len(id_de_type_as_generic_de_type(de_type), actual_len) - .map_err(|_e| LdtPostprocessError::InvalidLength)?; - buf[1..3].copy_from_slice(self.salt.bytes().as_slice()); - buf[3..17].copy_from_slice(&self.metadata_key.0); + fn header(&self) -> header::V0Header { + header::V0Header::ldt_short_salt(self.salt, self.identity_token) + } - // encrypt everything after DE header and salt - self.ldt_enc.encrypt(&mut buf[3..], &ldt_np_adv::salt_padder::<16, C>(self.salt)).map_err( - |e| match e { - // too short, not enough DEs -- should be caught by length validation above, though - ldt::LdtError::InvalidLength(_) => LdtPostprocessError::InvalidLength, - }, - ) + fn postprocess(&self, header_len: usize, buf: &mut [u8]) -> Result<(), LdtEncodeError> { + // encrypt everything after v0 format and salt + self.ldt_enc + .encrypt( + &mut buf[header_len - V0_IDENTITY_TOKEN_LEN..], + &ldt_np_adv::salt_padder::<C>(self.salt), + ) + .map_err(|e| match e { + // too short, not enough DEs + ldt::LdtError::InvalidLength(_) => LdtEncodeError::InvalidLength, + }) } } -/// Something went wrong, or preconditions were not met, during identity postprocessing. +/// LDT encoding errors #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum LdtPostprocessError { - /// The minimum size (2 bytes) or maximum size (6 bytes) of DE payload was not met +pub enum LdtEncodeError { + /// The minimum size (2 bytes) or maximum size (7 bytes for BLE 4.2 + /// advertisements) of DE data was not met InvalidLength, } +/// The serialized form of a V0 adv, suitable for setting as the value for the NP UUID svc data. +pub type SerializedAdv = ArrayView<u8, BLE_4_ADV_SVC_MAX_CONTENT_LEN>; + /// Accumulates DEs, then massages the serialized DEs with the configured identity to produce /// the final advertisement. #[derive(Debug)] -pub struct AdvBuilder<I: Identity> { +pub struct AdvBuilder<E: AdvEncoder> { /// The first byte is for the adv header, then the next I::OVERHEAD_LEN bytes are set aside for - /// use by [Identity::postprocess]. - buffer: [u8; BLE_ADV_SVC_CONTENT_LEN], + /// use by [AdvEncoder::postprocess]. + buffer: [u8; BLE_4_ADV_SVC_MAX_CONTENT_LEN], /// How much of the buffer is consumed. - /// Always <= buffer length + /// Always <= buffer length, and at least 2 len: usize, - identity: I, + /// How long the header was + header_len: usize, + encoder: E, } -impl<I: Identity> AdvBuilder<I> { +impl<E: AdvEncoder> AdvBuilder<E> { /// Create an empty AdvBuilder with the provided identity. - pub fn new(identity: I) -> AdvBuilder<I> { - // adv header + identity overhead - let len = 1 + I::OVERHEAD_LEN; + pub fn new(encoder: E) -> AdvBuilder<E> { + let mut buffer = [0; BLE_4_ADV_SVC_MAX_CONTENT_LEN]; + buffer[0] = E::VERSION_HEADER; + + // encode the rest of the V0 header + let header = encoder.header(); + let header_len = header.as_slice().len(); + // len will be at least 1, important for max_de_len safety in add_data_element + let len = 1 + header_len; // check for broken identities - assert!(len < BLE_ADV_SVC_CONTENT_LEN); + debug_assert!(len < buffer.len()); + buffer[1..=header_len].copy_from_slice(header.as_slice()); + AdvBuilder { // conveniently the first byte is already 0, which is the correct header for v0. // 3 bit version (000 since this is version 0), 5 bit reserved (also all 0) - buffer: [0; BLE_ADV_SVC_CONTENT_LEN], + buffer, len, - identity, + header_len, + encoder, } } /// Add the data element to the packet buffer, if there is space. - pub fn add_data_element<B: ToDataElementBundle<I::Flavor>>( + pub fn add_data_element<D: SerializeDataElement<E::Flavor>>( &mut self, - data_element: B, + data_element: D, ) -> Result<(), AddDataElementError> { - let remaining = self.buffer.len() - self.len; - let bundle = data_element.to_de_bundle(); - // length including header byte - let de_slice = bundle.contents_as_slice(); - let de_total_len = 1 + de_slice.len(); - if remaining < de_total_len { - return Err(AddDataElementError::InsufficientAdvSpace); - } + // invariant: self.len <= buffer length + debug_assert!(self.len <= self.buffer.len()); + let dest = &mut self.buffer[self.len..]; + // because self.len is at least 1, the dest will be no more than + // `[BLE_ADV_SVC_CONTENT_LEN] - 1 = [NP_MAX_ADV_CONTENT_LEN]` + let de_buf = serialize_de(&data_element, dest.len())?; + dest[..de_buf.len()].copy_from_slice(de_buf.as_slice()); + // invariant: de_buf fit in the remaining space, so adding its length is safe + self.len += de_buf.len(); + debug_assert!(self.len <= self.buffer.len()); - // header - self.buffer[self.len] = - encode_de_header(bundle.de_type.as_generic_de_type(), bundle.encoded_len); - self.len += 1; - // de contents - self.buffer[self.len..self.len + de_slice.len()].copy_from_slice(de_slice); - self.len += de_slice.len(); Ok(()) } - /// Return the finished advertisement (adv header + DEs), or `None` if the adv could not be - /// built. - pub fn into_advertisement( - mut self, - ) -> Result<ArrayView<u8, BLE_ADV_SVC_CONTENT_LEN>, I::Error> { + /// Return the finished advertisement (version header || V0 header || DEs), + /// or `None` if the adv could not be built. + pub fn into_advertisement(mut self) -> Result<SerializedAdv, E::Error> { // encrypt, if applicable - self.identity - // skip adv header for postprocessing - .postprocess(&mut self.buffer[1..self.len]) + self.encoder + // skip NP version header for postprocessing + .postprocess(self.header_len, &mut self.buffer[1..self.len]) .map(|_| ArrayView::try_from_array(self.buffer, self.len).expect("len is always valid")) } } @@ -271,131 +288,67 @@ InsufficientAdvSpace, } -/// The serialized form of a data element. -#[derive(Clone, Debug)] -pub struct DataElementBundle<F: PacketFlavor> { - de_type: PlainDataElementType, - /// Data element payload - data: DePayload, - /// The header-encoded form of `data`'s length - encoded_len: DeEncodedLength, - /// Type marker for whether this DE can be used in encrypted or plaintext packets. - flavor: marker::PhantomData<F>, +impl From<DataElementSerializeError> for AddDataElementError { + fn from(value: DataElementSerializeError) -> Self { + match value { + DataElementSerializeError::InsufficientSpace => Self::InsufficientAdvSpace, + } + } } -impl<F: PacketFlavor> DataElementBundle<F> { - /// Returns `Err` if the provided `data` or requested [PacketFlavor] are not valid for - /// `de_type`. - pub(crate) fn try_from( - de_type: PlainDataElementType, - data: &[u8], - ) -> Result<DataElementBundle<F>, DeBundleError> { - if !de_type.supports_flavor(F::ENUM_VARIANT) { - return Err(DeBundleError::InvalidFlavor); - } +/// Encode a DE type and length into a DE header byte. +pub(crate) fn encode_de_header(code: DeTypeCode, header_len: DeEncodedLength) -> u8 { + // 4 high bits are length, 4 low bits are type + (header_len.as_u8() << 4) | code.as_u8() +} - let mut buffer = [0; NP_MAX_DE_CONTENT_LEN]; - buffer - .get_mut(0..data.len()) - .map(|dest| dest.copy_from_slice(data)) - .ok_or(DeBundleError::InvalidLength)?; +/// Encode a DE into a buffer. +/// +/// The buffer will contain the DE header and DE contents, if any, and will +/// not exceed `max_de_len`. +/// +/// # Panics +/// `max_de_len` must be no larger than [NP_MAX_ADV_CONTENT_LEN]. +fn serialize_de<F: PacketFlavor, D: SerializeDataElement<F>>( + data_element: &D, + max_de_len: usize, +) -> Result<SerializedDataElement, AddDataElementError> { + let mut de_buf = DataElementSerializationBuffer::new(max_de_len) + .expect("max_de_len must not exceed NP_MAX_DE_CONTENT_LEN"); - let payload: DePayload = ArrayView::try_from_array(buffer, data.len()) - .expect("data already copied into buffer") - .into(); + // placeholder for header + de_buf.try_push(0).ok_or(AddDataElementError::InsufficientAdvSpace)?; + data_element.serialize_contents(&mut de_buf)?; - // get the encoded length now so we know the length is valid for the DE type - let encoded_len = de_type - .as_generic_de_type() - .encoded_len_for_actual_len(payload.len()) - .map_err(|_| DeBundleError::InvalidLength)?; + let encoded_len = data_element.map_actual_len_to_encoded_len( + DeActualLength::try_from(de_buf.len() - 1) + .expect("DE fit in buffer after header, so it should be a valid size"), + ); - Ok(DataElementBundle { de_type, data: payload, encoded_len, flavor: marker::PhantomData }) + let mut vec = de_buf.into_inner().into_inner(); + vec[0] = encode_de_header(data_element.de_type_code(), encoded_len); + + debug_assert!(vec.len() <= max_de_len); + + Ok(SerializedDataElement::new(to_array_view(vec))) +} + +/// The serialized form of a data element, including its header. +pub(crate) struct SerializedDataElement { + data: ArrayView<u8, NP_MAX_ADV_CONTENT_LEN>, +} + +impl SerializedDataElement { + fn new(data: ArrayView<u8, NP_MAX_ADV_CONTENT_LEN>) -> Self { + Self { data } } - /// The data contained in the DE, excluding the header byte - pub(crate) fn contents_as_slice(&self) -> &[u8] { + /// The serialized DE, starting with the DE header byte + pub(crate) fn as_slice(&self) -> &[u8] { self.data.as_slice() } -} -/// Errors that can occur when building a [DataElementBundle] -#[derive(Debug, PartialEq, Eq)] -pub(crate) enum DeBundleError { - /// The DE type does not support the requested flavor - InvalidFlavor, - /// The data is too long to fit in a DE, or is invalid for the DE type - InvalidLength, -} - -/// Implemented by higher-level types that represent data elements. -pub trait ToDataElementBundle<F: PacketFlavor> { - /// Serialize `self` into the impl-specific byte encoding used for that DE type. - fn to_de_bundle(&self) -> DataElementBundle<F>; -} - -// for cases where it's more convenient to already have a DataElementBundle than a DE -impl<F: PacketFlavor> ToDataElementBundle<F> for DataElementBundle<F> { - fn to_de_bundle(&self) -> DataElementBundle<F> { - Self { - de_type: self.de_type, - data: self.data.clone(), - encoded_len: self.encoded_len, - flavor: marker::PhantomData, - } - } -} - -// Biggest size a DE could possibly be is the entire payload -#[derive(Clone, PartialEq, Eq, Debug)] -struct DePayload { - payload: ArrayView<u8, { NP_MAX_DE_CONTENT_LEN }>, -} - -impl DePayload { - /// The actual length of the payload - fn len(&self) -> DeActualLength { - self.payload - .len() - .try_into() - .expect("Payload is an array of the max size which always has a valid length") - } - - fn as_slice(&self) -> &[u8] { - self.payload.as_slice() - } -} - -impl From<ArrayView<u8, { NP_MAX_DE_CONTENT_LEN }>> for DePayload { - fn from(array: ArrayView<u8, { NP_MAX_DE_CONTENT_LEN }>) -> Self { - Self { payload: array } - } -} - -/// Encode a DE type and length into a DE header byte. -pub(crate) fn encode_de_header(de_type: DataElementType, header_len: DeEncodedLength) -> u8 { - // 4 high bits are length, 4 low bits are type - (header_len.as_u8() << 4) | de_type.type_code().as_u8() -} - -/// Encode a DE type and length into a DE header byte. -pub(crate) fn encode_de_header_actual_len( - de_type: DataElementType, - header_len: DeActualLength, -) -> Result<u8, DeLengthOutOfRange> { - de_type - .encoded_len_for_actual_len(header_len) - // 4 high bits are length, 4 low bits are type - .map(|len| encode_de_header(de_type, len)) -} - -pub(crate) fn id_de_type_as_generic_de_type( - id_de_type: IdentityDataElementType, -) -> DataElementType { - match id_de_type { - IdentityDataElementType::Private => DataElementType::PrivateIdentity, - IdentityDataElementType::Trusted => DataElementType::TrustedIdentity, - IdentityDataElementType::Public => DataElementType::PublicIdentity, - IdentityDataElementType::Provisioned => DataElementType::ProvisionedIdentity, + pub(crate) fn len(&self) -> usize { + self.data.len() } }
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests.rs b/nearby/presence/np_adv/src/legacy/serialize/tests.rs deleted file mode 100644 index 7be30ba..0000000 --- a/nearby/presence/np_adv/src/legacy/serialize/tests.rs +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unwrap_used)] - -extern crate std; - -use crate::legacy::actions::FastPairSass; -use crate::legacy::actions::NearbyShare; -use crate::{ - credential::{v0::V0, SimpleBroadcastCryptoMaterial}, - de_type::EncryptedIdentityDataElementType, - legacy::{actions::*, data_elements::*, serialize::*}, - shared_data::TxPower, -}; -use crypto_provider_default::CryptoProviderImpl; -use ldt_np_adv::{salt_padder, LdtEncrypterXtsAes128, LegacySalt}; -use std::vec; - -#[test] -fn public_identity_packet_serialization() { - let mut builder = AdvBuilder::new(PublicIdentity); - - let tx_power = TxPower::try_from(3).unwrap(); - let mut action = ActionBits::default(); - action.set_action(NearbyShare::from(true)); - builder.add_data_element(TxPowerDataElement::from(tx_power)).unwrap(); - builder.add_data_element(ActionsDataElement::from(action)).unwrap(); - - let packet = builder.into_advertisement().unwrap(); - assert_eq!( - &[ - 0x00, // Adv Header - 0x03, // Public DE header - 0x15, 0x03, // Tx Power DE with value 3 - 0x26, 0x00, 0x40, // Actions DE w/ bit 9 - ], - packet.as_slice() - ); -} - -#[test] -fn packet_limits_capacity() { - let mut builder = AdvBuilder::new(PublicIdentity); - // 2 + 1 left out of 24 payload bytes - builder.len = 21; - let mut bits = ActionBits::default(); - bits.set_action(NearbyShare::from(true)); - bits.set_action(FastPairSass::from(true)); - - assert_eq!(Ok(()), builder.add_data_element(ActionsDataElement::from(bits))); - - // too small for 2+ 1 DE - builder.len = 22; - assert_eq!( - Err(AddDataElementError::InsufficientAdvSpace), - builder.add_data_element(ActionsDataElement::from(bits)) - ); -} - -#[test] -fn ldt_packet_serialization() { - // don't care about the HMAC since we're not decrypting - let key_seed = [0; 32]; - let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let ldt = LdtEncrypterXtsAes128::<CryptoProviderImpl>::new(&hkdf.legacy_ldt_key()); - let metadata_key = ShortMetadataKey([0x33; 14]); - let salt = LegacySalt::from([0x01, 0x02]); - - let mut ciphertext = vec![]; - ciphertext.extend_from_slice(&metadata_key.0); - // tx power & action DEs - ciphertext.extend_from_slice(&[0x15, 0x03, 0x26, 0x00, 0x10]); - ldt.encrypt(&mut ciphertext, &salt_padder::<16, CryptoProviderImpl>(salt)).unwrap(); - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); - - let mut builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - EncryptedIdentityDataElementType::Private, - salt, - &broadcast_cm, - )); - - let tx_power = TxPower::try_from(3).unwrap(); - let mut action = ActionBits::default(); - action.set_action(PhoneHub::from(true)); - builder.add_data_element(TxPowerDataElement::from(tx_power)).unwrap(); - builder.add_data_element(ActionsDataElement::from(action)).unwrap(); - - let packet = builder.into_advertisement().unwrap(); - // header - let mut expected = vec![0x00]; - // private header with five bytes after it - expected.push(0x51); - expected.extend_from_slice(salt.bytes()); - expected.extend_from_slice(&ciphertext); - assert_eq!(&expected, packet.as_slice()); -} - -#[test] -fn ldt_packet_cant_encrypt_without_des() { - let metadata_key = ShortMetadataKey([0x33; 14]); - let salt = LegacySalt::from([0x01, 0x02]); - let key_seed = [0xFE; 32]; - - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); - - let builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - EncryptedIdentityDataElementType::Private, - salt, - &broadcast_cm, - )); - - // not enough ciphertext - assert_eq!(Err(LdtPostprocessError::InvalidLength), builder.into_advertisement()); -} - -#[test] -fn nearby_share_action() { - let mut builder = AdvBuilder::new(PublicIdentity); - - let mut action = ActionBits::default(); - action.set_action(NearbyShare::from(true)); - - let actions_de = ActionsDataElement::from(action); - builder.add_data_element(actions_de).unwrap(); - - let tx_power_de = TxPowerDataElement::from(TxPower::try_from(-100).unwrap()); - builder.add_data_element(tx_power_de).unwrap(); - - assert_eq!( - &[ - 0x00, // version 0 - 0x03, // public identity - 0x26, // length 2, DE type 6 for actions - 0x00, 0x40, // bit 9 is active - 0x15, // length 1, DE type 5 for tx power - 0x9C, // tx power of -100 - ], - builder.into_advertisement().unwrap().as_slice() - ); -}
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests/error_conditions.rs b/nearby/presence/np_adv/src/legacy/serialize/tests/error_conditions.rs new file mode 100644 index 0000000..572276e --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/serialize/tests/error_conditions.rs
@@ -0,0 +1,193 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod unencrypted_encoder { + use alloc::vec; + use core::ops::Deref; + + extern crate std; + + use std::prelude::rust_2021::*; + + use crate::legacy::serialize::tests::helpers::{LongDataElement, ShortDataElement}; + use crate::legacy::serialize::{ + AddDataElementError, AdvBuilder, UnencryptedEncodeError, UnencryptedEncoder, + }; + use crate::legacy::{BLE_4_ADV_SVC_MAX_CONTENT_LEN, NP_MAX_DE_CONTENT_LEN}; + + #[test] + fn build_empty_adv_error() { + // empty isn't allowed, so 1 byte of payload is the smallest possible + let builder = AdvBuilder::new(UnencryptedEncoder); + + assert_eq!( + UnencryptedEncodeError::InvalidLength, + builder.into_advertisement().unwrap_err() + ); + } + + #[test] + fn add_de_when_full_error() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder + .add_data_element(LongDataElement::new(vec![1; NP_MAX_DE_CONTENT_LEN].clone())) + .unwrap(); + + // 1 more byte (DE header) is too much + assert_eq!( + AddDataElementError::InsufficientAdvSpace, + builder.add_data_element(ShortDataElement::new(vec![].clone())).unwrap_err() + ); + } + + #[test] + fn add_too_much_de_when_almost_full_error() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + // leave 1 byte of room + builder + .add_data_element(LongDataElement::new(vec![1; NP_MAX_DE_CONTENT_LEN - 1].clone())) + .unwrap(); + + // DE header would fit, but 1 byte of DE content is too much + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN - 1, builder.len); + assert_eq!( + AddDataElementError::InsufficientAdvSpace, + builder.add_data_element(ShortDataElement::new(vec![2].clone())).unwrap_err() + ); + } + + #[test] + fn broken_de_impl_hits_expected_panic() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + let panic_payload = std::panic::catch_unwind(move || { + // This DE type can't represent short lengths + builder.add_data_element(LongDataElement::new(vec![])) + }) + .unwrap_err(); + + assert_eq!( + "Couldn't encode actual len: DeLengthOutOfRange", + panic_payload.downcast::<String>().unwrap().deref() + ); + } +} + +mod ldt_encoder { + use alloc::string::String; + use alloc::vec; + use core::ops::Deref; + + extern crate std; + + use crypto_provider_default::CryptoProviderImpl; + use ldt_np_adv::{V0IdentityToken, V0Salt}; + + use crate::credential::v0::V0BroadcastCredential; + use crate::legacy::serialize::tests::helpers::{LongDataElement, ShortDataElement}; + use crate::legacy::serialize::{AddDataElementError, AdvBuilder, LdtEncodeError, LdtEncoder}; + use crate::legacy::BLE_4_ADV_SVC_MAX_CONTENT_LEN; + + #[test] + fn build_empty_adv_error() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let builder = AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + // not enough ciphertext + assert_eq!(Err(LdtEncodeError::InvalidLength), builder.into_advertisement()); + } + + #[test] + fn build_adv_one_byte_error() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + // 1 byte of DE header + builder.add_data_element(ShortDataElement::new(vec![])).unwrap(); + + // not enough ciphertext + assert_eq!(Err(LdtEncodeError::InvalidLength), builder.into_advertisement()); + } + + #[test] + fn add_de_when_full_error() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + // 7 bytes will fill it + builder.add_data_element(ShortDataElement::new(vec![1; 6])).unwrap(); + + // 1 more byte is too many + assert_eq!( + AddDataElementError::InsufficientAdvSpace, + builder.add_data_element(ShortDataElement::new(vec![])).unwrap_err() + ); + } + + #[test] + fn add_too_much_de_when_almost_full_error() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + // 6 bytes will leave 1 byte + builder.add_data_element(ShortDataElement::new(vec![1; 5])).unwrap(); + + // 1 byte would fit, but 2 won't + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN - 1, builder.len); + assert_eq!( + AddDataElementError::InsufficientAdvSpace, + builder.add_data_element(ShortDataElement::new(vec![2])).unwrap_err() + ); + } + + #[test] + fn broken_de_impl_hits_expected_panic() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + + let panic_payload = std::panic::catch_unwind(move || { + // This DE type can't represent short lengths + builder.add_data_element(LongDataElement::new(vec![])) + }) + .unwrap_err(); + + assert_eq!( + "Couldn't encode actual len: DeLengthOutOfRange", + panic_payload.downcast::<String>().unwrap().deref() + ); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests/happy_path.rs b/nearby/presence/np_adv/src/legacy/serialize/tests/happy_path.rs new file mode 100644 index 0000000..05fc20a --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/serialize/tests/happy_path.rs
@@ -0,0 +1,244 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod unencrypted_encoder { + use alloc::vec; + + use crate::header::VERSION_HEADER_V0_UNENCRYPTED; + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement, NearbyShare}; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::serialize::tests::helpers::{LongDataElement, ShortDataElement}; + use crate::legacy::serialize::{AdvBuilder, UnencryptedEncoder}; + use crate::legacy::{ + BLE_4_ADV_SVC_MAX_CONTENT_LEN, NP_MAX_ADV_CONTENT_LEN, NP_MAX_DE_CONTENT_LEN, + }; + use crate::shared_data::TxPower; + + #[test] + fn adv_min_size() { + // empty isn't allowed, so 1 byte of payload is the smallest possible + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder.add_data_element(ShortDataElement::new(vec![])).unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(&[VERSION_HEADER_V0_UNENCRYPTED, 0x0E], adv.as_slice()); + } + + #[test] + fn adv_max_size_multi_de() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder.add_data_element(ShortDataElement::new(vec![1; 10])).unwrap(); + // max len after previous DE & headers + let de2_contents = vec![2; NP_MAX_ADV_CONTENT_LEN - 1 - 10 - 1]; + builder.add_data_element(LongDataElement::new(de2_contents.clone())).unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, adv.len()); + assert_eq!( + &[ + [VERSION_HEADER_V0_UNENCRYPTED, 0xAE].as_slice(), + [1; 10].as_slice(), + &[0x4F], + &de2_contents + ] + .concat(), + adv.as_slice() + ); + } + + #[test] + fn adv_max_size_single_de() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder + .add_data_element(LongDataElement::new(vec![1; NP_MAX_DE_CONTENT_LEN].clone())) + .unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, adv.len()); + assert_eq!( + &[[VERSION_HEADER_V0_UNENCRYPTED, 0xFF].as_slice(), &[1; NP_MAX_DE_CONTENT_LEN],] + .concat(), + adv.as_slice() + ); + } + + #[rustfmt::skip] + #[test] + fn typical_tx_power_and_actions() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); + + let mut action = ActionBits::default(); + action.set_action(NearbyShare::from(true)); + builder.add_data_element(ActionsDataElement::from(action)).unwrap(); + + let packet = builder.into_advertisement().unwrap(); + assert_eq!( + &[ + VERSION_HEADER_V0_UNENCRYPTED, + 0x15, 0x03, // Tx Power DE with value 3 + 0x26, 0x00, 0x40, // Actions DE w/ bit 9 + ], + packet.as_slice() + ); + } +} + +mod ldt_encoder { + use alloc::vec; + + use crypto_provider_default::CryptoProviderImpl; + use ldt::LdtCipher; + use ldt_np_adv::{ + salt_padder, NpLdtEncryptCipher, V0IdentityToken, V0Salt, V0_IDENTITY_TOKEN_LEN, + }; + + use crate::credential::v0::V0BroadcastCredential; + use crate::header::VERSION_HEADER_V0_LDT; + use crate::legacy::data_elements::actions::tests::LastBit; + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement, PhoneHub}; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::serialize::tests::helpers::ShortDataElement; + use crate::legacy::serialize::{AdvBuilder, LdtEncoder, SerializedAdv}; + use crate::legacy::BLE_4_ADV_SVC_MAX_CONTENT_LEN; + use crate::shared_data::TxPower; + + #[test] + fn adv_min_size() { + // need at least 2 bytes to make 1 full block + let _ = assert_ldt_adv(&[0x1E, 0xAA], |builder| { + builder.add_data_element(ShortDataElement::new(vec![0xAA])).unwrap(); + }); + } + + #[test] + fn adv_max_size_multi_de() { + let adv = assert_ldt_adv(&[0x15, 0x03, 0x4E, 0x01, 0x01, 0x01, 0x01], |builder| { + builder + .add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())) + .unwrap(); + builder.add_data_element(ShortDataElement::new(vec![1; 4])).unwrap(); + }); + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, adv.len()); + } + + #[test] + fn adv_max_size_single_de() { + let adv = assert_ldt_adv(&[0x6E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], |builder| { + builder.add_data_element(ShortDataElement::new(vec![1; 6])).unwrap(); + }); + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN, adv.len()); + } + + #[test] + fn adv_tx_power_max_length_actions() { + let adv = assert_ldt_adv(&[0x15, 0x03, 0x36, 0x00, 0x00, 0x01], |builder| { + builder + .add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())) + .unwrap(); + let mut action = ActionBits::default(); + action.set_action(LastBit::from(true)); + builder.add_data_element(ActionsDataElement::from(action)).unwrap(); + }); + // TODO this should be the max adv size once action size gets increased + assert_eq!(BLE_4_ADV_SVC_MAX_CONTENT_LEN - 1, adv.len()); + } + + #[test] + fn adv_typical_tx_power_and_actions() { + let _ = assert_ldt_adv(&[0x15, 0x03, 0x26, 0x00, 0x10], |builder| { + builder + .add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())) + .unwrap(); + let mut action = ActionBits::default(); + action.set_action(PhoneHub::from(true)); + builder.add_data_element(ActionsDataElement::from(action)).unwrap(); + }); + } + + /// Build an LDT advertisement using the DEs provided by `add_des`, and assert that the resulting + /// advertisement matches the result of encrypting `identity token || after_identity_token` + fn assert_ldt_adv( + after_identity_token: &[u8], + add_des: impl Fn(&mut AdvBuilder<LdtEncoder<CryptoProviderImpl>>), + ) -> SerializedAdv { + let key_seed = [0; 32]; + let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); + let ldt = NpLdtEncryptCipher::<CryptoProviderImpl>::new(&hkdf.v0_ldt_key()); + let identity_token = V0IdentityToken::from([0x33; V0_IDENTITY_TOKEN_LEN]); + let salt = V0Salt::from([0x01, 0x02]); + + let mut plaintext = identity_token.as_slice().to_vec(); + plaintext.extend_from_slice(after_identity_token); + ldt.encrypt(&mut plaintext, &salt_padder::<CryptoProviderImpl>(salt)).unwrap(); + let ciphertext = plaintext; + + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + + let mut builder = + AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred)); + add_des(&mut builder); + + let adv = builder.into_advertisement().unwrap(); + + let mut expected = vec![VERSION_HEADER_V0_LDT]; + expected.extend_from_slice(&salt.bytes()); + expected.extend_from_slice(&ciphertext); + assert_eq!(&expected, adv.as_slice()); + adv + } +} + +mod tx_de { + use crate::header::VERSION_HEADER_V0_UNENCRYPTED; + use crate::legacy::data_elements::tx_power::TxPowerDataElement; + use crate::legacy::serialize::{AdvBuilder, UnencryptedEncoder}; + use crate::shared_data::TxPower; + + #[test] + fn tx_power_produces_1_byte() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(&[VERSION_HEADER_V0_UNENCRYPTED, 0x15, 0x03], adv.as_slice()); + } +} + +mod actions_de { + use crate::header::VERSION_HEADER_V0_UNENCRYPTED; + use crate::legacy::data_elements::actions::tests::LastBit; + use crate::legacy::data_elements::actions::{ActionBits, ActionsDataElement}; + use crate::legacy::serialize::{AdvBuilder, UnencryptedEncoder}; + + #[test] + fn no_bits_set_produces_1_byte() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + builder.add_data_element(ActionsDataElement::from(ActionBits::default())).unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(&[VERSION_HEADER_V0_UNENCRYPTED, 0x16, 0x00], adv.as_slice()); + } + + #[test] + fn lowest_bit_set_produces_max_len() { + let mut builder = AdvBuilder::new(UnencryptedEncoder); + + let mut bits = ActionBits::default(); + bits.set_action(LastBit::from(true)); + builder.add_data_element(ActionsDataElement::from(bits)).unwrap(); + let adv = builder.into_advertisement().unwrap(); + assert_eq!(&[VERSION_HEADER_V0_UNENCRYPTED, 0x36, 0x00, 0x00, 0x01], adv.as_slice()); + } +}
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests/helpers.rs b/nearby/presence/np_adv/src/legacy/serialize/tests/helpers.rs new file mode 100644 index 0000000..ea0c886 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/serialize/tests/helpers.rs
@@ -0,0 +1,176 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate std; + +use std::prelude::rust_2021::*; + +use sink::Sink; + +use crate::legacy::data_elements::{ + DataElementDeserializeError, DeserializeDataElement, DirectMapPredicate, DirectMapper, + LengthMapper, +}; +use crate::{ + legacy::{ + data_elements::{ + de_type::{DeActualLength, DeEncodedLength, DeTypeCode, MAX_DE_ENCODED_LEN}, + DataElementSerializationBuffer, DataElementSerializeError, SerializeDataElement, + }, + PacketFlavor, NP_MAX_DE_CONTENT_LEN, + }, + private::Sealed, + DeLengthOutOfRange, +}; + +/// A DE allowing arbitrary data lengths. Encoded length is offset from actual length. +/// +/// Data longer than [NP_MAX_DE_CONTENT_LEN] or shorter than [NP_MAX_DE_CONTENT_LEN] - [MAX_DE_ENCODED_LEN] +/// will fail to map the actual length. +#[derive(Debug, PartialEq, Eq, Clone)] +pub(crate) struct LongDataElement { + data: Vec<u8>, +} + +impl LongDataElement { + /// The offset lengths are shifted by when encoded + // `as usize` is safe since all u8s can fit. Can't use .into() or ::from() in a const. + pub(in crate::legacy) const OFFSET: usize = + NP_MAX_DE_CONTENT_LEN - (MAX_DE_ENCODED_LEN as usize); + pub fn new(data: Vec<u8>) -> Self { + Self { data } + } +} + +impl Sealed for LongDataElement {} + +impl<F: PacketFlavor> SerializeDataElement<F> for LongDataElement { + fn de_type_code(&self) -> DeTypeCode { + Self::DE_TYPE_CODE + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + <Self as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual_len) + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + sink.try_extend_from_slice(&self.data).ok_or(DataElementSerializeError::InsufficientSpace) + } +} + +impl DeserializeDataElement for LongDataElement { + const DE_TYPE_CODE: DeTypeCode = match DeTypeCode::try_from(15) { + Ok(t) => t, + Err(_) => unreachable!(), + }; + type LengthMapper = OffsetMapper<{ Self::OFFSET }>; + + fn deserialize<F: PacketFlavor>( + de_contents: &[u8], + ) -> Result<Self, DataElementDeserializeError> { + Ok(Self { data: de_contents.to_vec() }) + } +} + +impl From<Vec<u8>> for LongDataElement { + fn from(value: Vec<u8>) -> Self { + Self { data: value } + } +} + +/// Subtracts `O` from actual lengths to yield encoded lengths, and vice versa. +pub(in crate::legacy) struct OffsetMapper<const O: usize>; + +impl<const O: usize> LengthMapper for OffsetMapper<O> { + fn map_encoded_len_to_actual_len( + encoded_len: DeEncodedLength, + ) -> Result<DeActualLength, DeLengthOutOfRange> { + DeActualLength::try_from(encoded_len.as_usize() + O) + } + + fn map_actual_len_to_encoded_len(actual_len: DeActualLength) -> DeEncodedLength { + actual_len + .as_u8() + .checked_sub(O.try_into().expect("Actual len is too short to use offset")) + .ok_or(DeLengthOutOfRange) + .and_then(DeEncodedLength::try_from) + .expect("Couldn't encode actual len") + } +} + +/// A DE allowing arbitrary data with a straightforward actual len = encoded len scheme. +/// +/// Data longer than [MAX_DE_ENCODED_LEN] will fail when mapping the length. +#[derive(Debug, PartialEq, Eq, Clone)] +pub(crate) struct ShortDataElement { + data: Vec<u8>, +} + +impl ShortDataElement { + pub fn new(data: Vec<u8>) -> Self { + Self { data } + } +} + +impl Sealed for ShortDataElement {} + +impl<F: PacketFlavor> SerializeDataElement<F> for ShortDataElement { + fn de_type_code(&self) -> DeTypeCode { + Self::DE_TYPE_CODE + } + + fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { + <Self as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual_len) + } + + fn serialize_contents( + &self, + sink: &mut DataElementSerializationBuffer, + ) -> Result<(), DataElementSerializeError> { + sink.try_extend_from_slice(&self.data).ok_or(DataElementSerializeError::InsufficientSpace) + } +} + +impl DeserializeDataElement for ShortDataElement { + const DE_TYPE_CODE: DeTypeCode = match DeTypeCode::try_from(14) { + Ok(t) => t, + Err(_) => unreachable!(), + }; + + type LengthMapper = DirectMapper<YoloLengthPredicate>; + + fn deserialize<F: PacketFlavor>( + de_contents: &[u8], + ) -> Result<Self, DataElementDeserializeError> { + Ok(Self { data: de_contents.to_vec() }) + } +} + +/// Approves all lengths +pub(in crate::legacy) struct YoloLengthPredicate; + +impl DirectMapPredicate for YoloLengthPredicate { + fn is_valid(_len: usize) -> bool { + true + } +} + +impl From<Vec<u8>> for ShortDataElement { + fn from(value: Vec<u8>) -> Self { + Self { data: value } + } +}
diff --git a/nearby/presence/np_adv/src/legacy/serialize/tests/mod.rs b/nearby/presence/np_adv/src/legacy/serialize/tests/mod.rs new file mode 100644 index 0000000..caaa7d8 --- /dev/null +++ b/nearby/presence/np_adv/src/legacy/serialize/tests/mod.rs
@@ -0,0 +1,95 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use crate::legacy::{ + data_elements::de_type::DataElementType, data_elements::*, serialize::*, PacketFlavorEnum, +}; + +mod error_conditions; +mod happy_path; +pub(in crate::legacy) mod helpers; + +pub(crate) fn serialize<F: PacketFlavor, D: SerializeDataElement<F>>( + de: &D, +) -> SerializedDataElement { + serialize_de(de, NP_MAX_ADV_CONTENT_LEN).unwrap() +} + +pub(in crate::legacy) fn supports_flavor(t: DataElementType, flavor: PacketFlavorEnum) -> bool { + match t { + DataElementType::Actions => match flavor { + PacketFlavorEnum::Plaintext => true, + PacketFlavorEnum::Ciphertext => true, + }, + DataElementType::TxPower => match flavor { + PacketFlavorEnum::Plaintext => true, + PacketFlavorEnum::Ciphertext => true, + }, + } +} + +mod coverage_gaming { + use crate::credential::v0::V0BroadcastCredential; + use crate::legacy::serialize::{ + AddDataElementError, AdvBuilder, LdtEncodeError, LdtEncoder, UnencryptedEncodeError, + UnencryptedEncoder, + }; + use alloc::format; + use crypto_provider_default::CryptoProviderImpl; + use ldt_np_adv::{V0IdentityToken, V0Salt}; + + #[test] + fn unencrypted_encoder() { + let _ = format!("{:?}", UnencryptedEncoder); + } + + #[test] + fn unencrypted_encoder_error() { + let _ = format!("{:?}", UnencryptedEncodeError::InvalidLength); + } + + #[test] + fn ldt_encoder_display() { + let identity_token = V0IdentityToken::from([0x33; 14]); + let salt = V0Salt::from([0x01, 0x02]); + let key_seed = [0xFE; 32]; + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); + let ldt_encoder = LdtEncoder::<CryptoProviderImpl>::new(salt, &broadcast_cred); + + // doesn't leak crypto material + assert_eq!("LdtEncoder { salt: V0Salt { bytes: [1, 2] } }", format!("{:?}", ldt_encoder)); + } + + #[test] + fn ldt_encoder_error() { + // debug, clone + let _ = format!("{:?}", LdtEncodeError::InvalidLength.clone()); + } + + #[test] + fn add_data_element_error() { + // debug + let _ = format!("{:?}", AddDataElementError::InsufficientAdvSpace); + } + + #[test] + fn adv_builder() { + // debug + let _ = format!("{:?}", AdvBuilder::new(UnencryptedEncoder)); + } +}
diff --git a/nearby/presence/np_adv/src/lib.rs b/nearby/presence/np_adv/src/lib.rs index 0b6d7ae..eb2ef0f 100644 --- a/nearby/presence/np_adv/src/lib.rs +++ b/nearby/presence/np_adv/src/lib.rs
@@ -21,56 +21,37 @@ #![no_std] #![allow(clippy::expect_used, clippy::indexing_slicing, clippy::panic)] -use crate::{ - credential::{ - book::CredentialBook, v0::V0DiscoveryCryptoMaterial, v0::V0, v1::V1DiscoveryCryptoMaterial, - v1::V1, DiscoveryCryptoMaterial, MatchedCredential, ProtocolVersion, - ReferencedMatchedCredential, - }, - deserialization_arena::ArenaOutOfSpace, - extended::deserialize::{ - encrypted_section::*, parse_sections, CiphertextSection, DataElementParseError, - DataElementParsingIterator, DecryptedSection, IntermediateSection, PlaintextSection, - Section, SectionDeserializeError, - }, - legacy::deserialize::{ - DecryptError, DecryptedAdvContents, IntermediateAdvContents, PlaintextAdvContents, - }, -}; - #[cfg(any(test, feature = "alloc"))] extern crate alloc; -#[cfg(any(test, feature = "alloc"))] -use alloc::vec::Vec; -use array_vec::ArrayVecOption; -#[cfg(feature = "devtools")] -use array_view::ArrayView; -use core::fmt::Debug; -use crypto_provider::CryptoProvider; -use deserialization_arena::{DeserializationArena, DeserializationArenaAllocator}; -#[cfg(feature = "devtools")] -use extended::NP_ADV_MAX_SECTION_LEN; -use extended::NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT; -use legacy::{data_elements::DataElementDeserializeError, deserialize::AdvDeserializeError}; -use nom::{combinator, number}; pub use strum; -mod array_vec; +use crate::credential::matched::MatchedCredential; +use crate::extended::deserialize::{deser_decrypt_v1, V1AdvertisementContents}; +use crate::{ + credential::book::CredentialBook, + header::NpVersionHeader, + legacy::{deser_decrypt_v0, V0AdvertisementContents}, +}; +use core::fmt::Debug; +use crypto_provider::CryptoProvider; +use deserialization_arena::DeserializationArena; +use legacy::data_elements::DataElementDeserializeError; + +#[cfg(test)] +mod tests; + pub mod credential; -pub mod de_type; -#[cfg(test)] -mod deser_v0_tests; -#[cfg(test)] -mod deser_v1_tests; pub mod deserialization_arena; pub mod extended; pub mod filter; -#[cfg(test)] -mod header_parse_tests; pub mod legacy; pub mod shared_data; +mod array_vec; +mod header; +mod helpers; + /// Canonical form of NP's service UUID. /// /// Note that UUIDs are encoded in BT frames in little-endian order, so these bytes may need to be @@ -88,356 +69,16 @@ B: CredentialBook<'cred>, P: CryptoProvider, { - let (remaining, header) = - parse_adv_header(adv).map_err(|_e| AdvDeserializationError::HeaderParseError)?; + let (remaining, header) = NpVersionHeader::parse(adv) + .map_err(|_e| AdvDeserializationError::VersionHeaderParseError)?; match header { - AdvHeader::V0 => { - deser_decrypt_v0::<B, P>(cred_book, remaining).map(DeserializedAdvertisement::V0) - } - AdvHeader::V1(header) => deser_decrypt_v1::<B, P>(arena, cred_book, remaining, header) - .map(DeserializedAdvertisement::V1), - } -} - -/// The encryption scheme used for a V1 advertisement. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum V1EncryptionScheme { - /// Indicates MIC-based encryption and verification. - Mic, - /// Indicates signature-based encryption and verification. - Signature, -} - -/// Error in decryption operations for `deser_decrypt_v1_section_bytes_for_dev_tools`. -#[cfg(feature = "devtools")] -#[derive(Debug, Clone)] -pub enum AdvDecryptionError { - /// Cannot decrypt because the input section is not encrypted. - InputNotEncrypted, - /// Error parsing the given section. - ParseError, - /// No suitable credential found to decrypt the given section. - NoMatchingCredentials, -} - -/// Decrypt, but do not further deserialize the v1 bytes, intended for developer tooling uses only. -/// Production uses should use [deserialize_advertisement] instead, which deserializes to a -/// structured format and provides extra type safety. -#[cfg(feature = "devtools")] -pub fn deser_decrypt_v1_section_bytes_for_dev_tools<'adv, 'cred, B, P>( - arena: DeserializationArena<'adv>, - cred_book: &'cred B, - header_byte: u8, - section_bytes: &'adv [u8], -) -> Result<(ArrayView<u8, NP_ADV_MAX_SECTION_LEN>, V1EncryptionScheme), AdvDecryptionError> -where - B: CredentialBook<'cred>, - P: CryptoProvider, -{ - let header = V1Header { header_byte }; - let int_sections = - parse_sections(header, section_bytes).map_err(|_| AdvDecryptionError::ParseError)?; - let cipher_section = match &int_sections[0] { - IntermediateSection::Plaintext(_) => Err(AdvDecryptionError::InputNotEncrypted)?, - IntermediateSection::Ciphertext(section) => section, - }; - - let mut allocator = arena.into_allocator(); - for (crypto_material, _) in cred_book.v1_iter() { - if let Some(plaintext) = cipher_section - .try_resolve_identity_and_decrypt::<_, P>(&mut allocator, &crypto_material) - { - let pt = plaintext.expect(concat!( - "Should not run out of space because DeserializationArenaAllocator is big ", - "enough to hold a single advertisement, and we exit immediately upon ", - "successful decryption", - )); - - let encryption_scheme = match cipher_section { - CiphertextSection::SignatureEncryptedIdentity(_) => V1EncryptionScheme::Signature, - CiphertextSection::MicEncryptedIdentity(_) => V1EncryptionScheme::Mic, - }; - return Ok((pt, encryption_scheme)); + NpVersionHeader::V0(encoding) => deser_decrypt_v0::<B, P>(encoding, cred_book, remaining) + .map(DeserializedAdvertisement::V0), + NpVersionHeader::V1(header) => { + deser_decrypt_v1::<B, P>(arena, cred_book, remaining, header) + .map(DeserializedAdvertisement::V1) } } - Err(AdvDecryptionError::NoMatchingCredentials) -} - -/// A ciphertext section which has not yet been -/// resolved to an identity, but for which some -/// `SectionIdentityResolutionContents` have been -/// pre-computed for speedy identity-resolution. -struct ResolvableCiphertextSection<'a> { - identity_resolution_contents: SectionIdentityResolutionContents, - ciphertext_section: CiphertextSection<'a>, -} - -/// A collection of possibly-deserialized sections which are separated according -/// to whether/not they're intermediate encrypted sections (of either type) -/// or fully-deserialized, with a running count of the number of malformed sections. -/// Each potentially-valid section is tagged with a 0-based index derived from the original -/// section ordering as they appeared within the original advertisement to ensure -/// that the fully-deserialized advertisement may be correctly reconstructed. -struct SectionsInProcessing<'adv, M: MatchedCredential> { - deserialized_sections: ArrayVecOption< - (usize, V1DeserializedSection<'adv, M>), - { NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT }, - >, - encrypted_sections: ArrayVecOption< - (usize, ResolvableCiphertextSection<'adv>), - { NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT }, - >, - malformed_sections_count: usize, -} - -impl<'adv, M: MatchedCredential> SectionsInProcessing<'adv, M> { - /// Attempts to parse a V1 advertisement's contents after the version header - /// into a collection of not-yet-fully-deserialized sections which may - /// require credentials to be decrypted. - fn from_advertisement_contents<C: CryptoProvider>( - header: V1Header, - remaining: &'adv [u8], - ) -> Result<Self, AdvDeserializationError> { - let int_sections = - parse_sections(header, remaining).map_err(|_| AdvDeserializationError::ParseError { - details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError, - })?; - let mut deserialized_sections = ArrayVecOption::default(); - let mut encrypted_sections = ArrayVecOption::default(); - // keep track of ordering for later sorting during `self.finished_with_decryption_attempts()`. - for (idx, s) in int_sections.into_iter().enumerate() { - match s { - IntermediateSection::Plaintext(p) => { - deserialized_sections.push((idx, V1DeserializedSection::Plaintext(p))) - } - IntermediateSection::Ciphertext(ciphertext_section) => { - let identity_resolution_contents = - ciphertext_section.contents().compute_identity_resolution_contents::<C>(); - let resolvable_ciphertext_section = ResolvableCiphertextSection { - identity_resolution_contents, - ciphertext_section, - }; - encrypted_sections.push((idx, resolvable_ciphertext_section)); - } - } - } - Ok(Self { deserialized_sections, encrypted_sections, malformed_sections_count: 0 }) - } - - /// Returns true iff we have resolved all sections to identities. - fn resolved_all_identities(&self) -> bool { - self.encrypted_sections.is_empty() - } - - /// Runs through all of the encrypted sections in processing, and attempts - /// to use the given credential to decrypt them. Suitable for situations - /// where iterating over credentials is relatively slow compared to - /// the cost of iterating over sections-in-memory. - fn try_decrypt_with_credential<C: V1DiscoveryCryptoMaterial, P: CryptoProvider>( - &mut self, - arena: &mut DeserializationArenaAllocator<'adv>, - crypto_material: C, - match_data: M, - ) -> Result<(), ArenaOutOfSpace> { - let mut i = 0; - while i < self.encrypted_sections.len() { - let (section_idx, section): &(usize, ResolvableCiphertextSection) = - &self.encrypted_sections[i]; - // Fast-path: Check for an identity match, ignore if there's no identity match. - let identity_resolution_contents = §ion.identity_resolution_contents; - let identity_resolution_material = match §ion.ciphertext_section { - CiphertextSection::MicEncryptedIdentity(_) => crypto_material - .unsigned_identity_resolution_material::<P>() - .into_raw_resolution_material(), - CiphertextSection::SignatureEncryptedIdentity(_) => crypto_material - .signed_identity_resolution_material::<P>() - .into_raw_resolution_material(), - }; - match identity_resolution_contents.try_match::<P>(&identity_resolution_material) { - None => { - // Try again with another section - i += 1; - continue; - } - Some(identity_match) => { - // The identity matched, so now we need to more closely scrutinize - // the provided ciphertext. Try to decrypt and parse the section. - let metadata_nonce = crypto_material.metadata_nonce::<P>(); - let deserialization_result = match §ion.ciphertext_section { - CiphertextSection::SignatureEncryptedIdentity(c) => c - .try_deserialize( - arena, - identity_match, - &crypto_material.signed_verification_material::<P>(), - ) - .map_err(SectionDeserializeError::from), - CiphertextSection::MicEncryptedIdentity(c) => c - .try_deserialize( - arena, - identity_match, - &crypto_material.unsigned_verification_material::<P>(), - ) - .map_err(SectionDeserializeError::from), - }; - match deserialization_result { - Ok(s) => { - self.deserialized_sections.push(( - *section_idx, - V1DeserializedSection::Decrypted(WithMatchedCredential::new( - match_data.clone(), - metadata_nonce, - s, - )), - )); - } - Err(e) => match e { - SectionDeserializeError::IncorrectCredential => { - // keep it around to try with another credential - i += 1; - continue; - } - SectionDeserializeError::ParseError => { - // the credential worked, but the section itself was bogus - self.malformed_sections_count += 1; - } - SectionDeserializeError::ArenaOutOfSpace => { - return Err(ArenaOutOfSpace) - } - }, - } - // By default, if we have an identity match, assume that decrypting the section worked, - // or that the section was somehow invalid. - // We don't care about maintaining order, so use O(1) remove - let _ = self.encrypted_sections.swap_remove(i); - // don't advance i -- it now points to a new element - } - } - } - Ok(()) - } - - /// Packages the current state of the deserialization process into a - /// `V1AdvertisementContents` representing a fully-deserialized V1 advertisement. - /// - /// This method should only be called after all sections were either successfully - /// decrypted or have had all relevant credentials checked against - /// them without obtaining a successful identity-match and/or subsequent - /// cryptographic verification of the section contents. - fn finished_with_decryption_attempts(mut self) -> V1AdvertisementContents<'adv, M> { - // Invalid sections = malformed sections + number of encrypted sections - // which we could not manage to decrypt with any of our credentials - let invalid_sections_count = self.malformed_sections_count + self.encrypted_sections.len(); - - // Put the deserialized sections back into the original ordering for - // the returned `V1AdvertisementContents` - // (Note: idx is unique, so unstable sort is ok) - self.deserialized_sections.sort_unstable_by_key(|(idx, _section)| *idx); - let ordered_sections = self.deserialized_sections.into_iter().map(|(_idx, s)| s).collect(); - V1AdvertisementContents::new(ordered_sections, invalid_sections_count) - } -} - -/// Deserialize and decrypt the contents of a v1 adv after the version header -fn deser_decrypt_v1<'adv, 'cred, B, P>( - arena: DeserializationArena<'adv>, - cred_book: &'cred B, - remaining: &'adv [u8], - header: V1Header, -) -> Result<V1AdvertisementContents<'adv, B::Matched>, AdvDeserializationError> -where - B: CredentialBook<'cred>, - P: CryptoProvider, -{ - let mut sections_in_processing = - SectionsInProcessing::<'_, B::Matched>::from_advertisement_contents::<P>( - header, remaining, - )?; - - let mut allocator = arena.into_allocator(); - - // Hot loop - // We assume that iterating credentials is more expensive than iterating sections - for (crypto_material, match_data) in cred_book.v1_iter() { - sections_in_processing - .try_decrypt_with_credential::<_, P>(&mut allocator, crypto_material, match_data) - .expect(concat!( - "Should not run out of space because DeserializationArenaAllocator is big ", - "enough to hold a single advertisement, and we exit immediately upon ", - "successful decryption", - )); - if sections_in_processing.resolved_all_identities() { - // No need to consider the other credentials - break; - } - } - Ok(sections_in_processing.finished_with_decryption_attempts()) -} - -/// Deserialize and decrypt the contents of a v0 adv after the version header -fn deser_decrypt_v0<'adv, 'cred, B, P>( - cred_book: &'cred B, - remaining: &'adv [u8], -) -> Result<V0AdvertisementContents<'adv, B::Matched>, AdvDeserializationError> -where - B: CredentialBook<'cred>, - P: CryptoProvider, -{ - let contents = legacy::deserialize::deserialize_adv_contents::<P>(remaining)?; - match contents { - IntermediateAdvContents::Plaintext(p) => Ok(V0AdvertisementContents::Plaintext(p)), - IntermediateAdvContents::Ciphertext(c) => { - for (crypto_material, matched) in cred_book.v0_iter() { - let ldt = crypto_material.ldt_adv_cipher::<P>(); - match c.try_decrypt(&ldt) { - Ok(c) => { - let metadata_nonce = crypto_material.metadata_nonce::<P>(); - return Ok(V0AdvertisementContents::Decrypted(WithMatchedCredential::new( - matched, - metadata_nonce, - c, - ))); - } - Err(e) => match e { - DecryptError::DecryptOrVerifyError => continue, - DecryptError::DeserializeError(e) => { - return Err(e.into()); - } - }, - } - } - Ok(V0AdvertisementContents::NoMatchingCredentials) - } - } -} - -/// Parse a NP advertisement header. -/// -/// This can be used on all versions of advertisements since it's the header that determines the -/// version. -/// -/// Returns a `nom::IResult` with the parsed header and the remaining bytes of the advertisement. -fn parse_adv_header(adv: &[u8]) -> nom::IResult<&[u8], AdvHeader> { - // header bits: VVVxxxxx - let (remaining, (header_byte, version, _low_bits)) = combinator::verify( - // splitting a byte at a bit boundary to take lower 5 bits - combinator::map(number::complete::u8, |byte| (byte, byte >> 5, byte & 0x1F)), - |&(_header_byte, version, low_bits)| match version { - // reserved bits, for any version, must be zero - PROTOCOL_VERSION_LEGACY | PROTOCOL_VERSION_EXTENDED => low_bits == 0, - _ => false, - }, - )(adv)?; - match version { - PROTOCOL_VERSION_LEGACY => Ok((remaining, AdvHeader::V0)), - PROTOCOL_VERSION_EXTENDED => Ok((remaining, AdvHeader::V1(V1Header { header_byte }))), - _ => unreachable!(), - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub(crate) enum AdvHeader { - V0, - V1(V1Header), } /// An NP advertisement with its header parsed. @@ -470,219 +111,11 @@ } } -/// The contents of a deserialized and decrypted V1 advertisement. -#[derive(Debug, PartialEq, Eq)] -pub struct V1AdvertisementContents<'adv, M: MatchedCredential> { - sections: ArrayVecOption<V1DeserializedSection<'adv, M>, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT>, - invalid_sections: usize, -} - -impl<'adv, M: MatchedCredential> V1AdvertisementContents<'adv, M> { - fn new( - sections: ArrayVecOption< - V1DeserializedSection<'adv, M>, - NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT, - >, - invalid_sections: usize, - ) -> Self { - Self { sections, invalid_sections } - } - - /// Destructures this V1 advertisement into just the sections - /// which could be successfully deserialized and decrypted - pub fn into_sections( - self, - ) -> ArrayVecOption<V1DeserializedSection<'adv, M>, NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT> { - self.sections - } - - /// The sections that could be successfully deserialized and decrypted - pub fn sections(&self) -> impl ExactSizeIterator<Item = &V1DeserializedSection<M>> { - self.sections.iter() - } - - /// The number of sections that could not be parsed or decrypted. - pub fn invalid_sections_count(&self) -> usize { - self.invalid_sections - } -} - -/// Advertisement content that was either already plaintext or has been decrypted. -#[derive(Debug, PartialEq, Eq)] -pub enum V0AdvertisementContents<'adv, M: MatchedCredential> { - /// Contents of an originally plaintext advertisement - Plaintext(PlaintextAdvContents<'adv>), - /// Contents that was ciphertext in the original advertisement, and has been decrypted - /// with the credential in the [MatchedCredential] - Decrypted(WithMatchedCredential<M, DecryptedAdvContents>), - /// The advertisement was encrypted, but no credentials matched - NoMatchingCredentials, -} - -/// Advertisement content that was either already plaintext or has been decrypted. -#[derive(Debug, PartialEq, Eq)] -pub enum V1DeserializedSection<'adv, M: MatchedCredential> { - /// Section that was plaintext in the original advertisement - Plaintext(PlaintextSection<'adv>), - /// Section that was ciphertext in the original advertisement, and has been decrypted - /// with the credential in the [MatchedCredential] - Decrypted(WithMatchedCredential<M, DecryptedSection<'adv>>), -} - -impl<'adv, M> Section<'adv, DataElementParseError> for V1DeserializedSection<'adv, M> -where - M: MatchedCredential, -{ - type Iterator = DataElementParsingIterator<'adv>; - - fn iter_data_elements(&self) -> Self::Iterator { - match self { - V1DeserializedSection::Plaintext(p) => p.iter_data_elements(), - V1DeserializedSection::Decrypted(d) => d.contents.iter_data_elements(), - } - } -} - -/// 16-byte metadata keys, as employed for metadata decryption. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub struct MetadataKey(pub [u8; 16]); - -impl AsRef<[u8]> for MetadataKey { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -/// Common trait to deserialized, decrypted V0 advs and V1 sections which -/// exposes relevant data about matched identities. -pub trait HasIdentityMatch { - /// The protocol version for which this advertisement - /// content has an identity-match. - type Version: ProtocolVersion; - - /// Gets the decrypted plaintext version-specific - /// metadata key for the associated identity. - fn metadata_key(&self) -> <Self::Version as ProtocolVersion>::MetadataKey; -} - -impl HasIdentityMatch for legacy::ShortMetadataKey { - type Version = V0; - fn metadata_key(&self) -> Self { - *self - } -} - -impl HasIdentityMatch for MetadataKey { - type Version = V1; - fn metadata_key(&self) -> Self { - *self - } -} - -#[cfg(any(test, feature = "alloc"))] -/// Type for errors from [`WithMatchedCredential#decrypt_metadata`] -#[derive(Debug)] -pub enum MatchedMetadataDecryptionError<M: MatchedCredential> { - /// Retrieving the encrypted metadata failed for one reason - /// or another, so we didn't get a chance to try decryption. - RetrievalFailed(<M as MatchedCredential>::EncryptedMetadataFetchError), - /// The encrypted metadata could be retrieved, but it did - /// not successfully decrypt against the matched identity. - /// This could be an indication of data corruption or - /// of malformed crypto on the sender-side. - DecryptionFailed, -} - -/// Decrypted advertisement content with the [MatchedCredential] from the credential that decrypted -/// it, along with any other information which is relevant to the identity-match. -#[derive(Debug, PartialEq, Eq)] -pub struct WithMatchedCredential<M: MatchedCredential, T: HasIdentityMatch> { - matched: M, - /// The 12-byte metadata nonce as derived from the key-seed HKDF - /// to be used for decrypting the encrypted metadata in the attached - /// matched-credential. - metadata_nonce: [u8; 12], - contents: T, -} -impl<'a, M: MatchedCredential + Clone, T: HasIdentityMatch> - WithMatchedCredential<ReferencedMatchedCredential<'a, M>, T> -{ - /// Clones the referenced match-data to update this container - /// so that the match-data is owned, rather than borrowed. - pub fn clone_match_data(self) -> WithMatchedCredential<M, T> { - let matched = self.matched.as_ref().clone(); - let metadata_nonce = self.metadata_nonce; - let contents = self.contents; - - WithMatchedCredential { matched, metadata_nonce, contents } - } -} -impl<M: MatchedCredential, T: HasIdentityMatch> WithMatchedCredential<M, T> { - fn new(matched: M, metadata_nonce: [u8; 12], contents: T) -> Self { - Self { matched, metadata_nonce, contents } - } - /// Applies the given function to the wrapped contents, yielding - /// a new instance with the same matched-credential. - pub fn map<R: HasIdentityMatch>( - self, - mapping: impl FnOnce(T) -> R, - ) -> WithMatchedCredential<M, R> { - let contents = mapping(self.contents); - let matched = self.matched; - let metadata_nonce = self.metadata_nonce; - WithMatchedCredential { matched, metadata_nonce, contents } - } - /// Credential data for the credential that decrypted the content. - pub fn matched_credential(&self) -> &M { - &self.matched - } - /// The decrypted advertisement content. - pub fn contents(&self) -> &T { - &self.contents - } - - #[cfg(any(test, feature = "alloc"))] - fn decrypt_metadata_from_fetch<C: CryptoProvider>( - &self, - encrypted_metadata: &[u8], - ) -> Result<Vec<u8>, MatchedMetadataDecryptionError<M>> { - let metadata_key = self.contents.metadata_key(); - <<T as HasIdentityMatch>::Version as ProtocolVersion>::decrypt_metadata::<C>( - self.metadata_nonce, - metadata_key, - encrypted_metadata, - ) - .map_err(|_| MatchedMetadataDecryptionError::DecryptionFailed) - } - - #[cfg(any(test, feature = "alloc"))] - /// Attempts to decrypt the encrypted metadata - /// associated with the matched credential - /// based on the details of the identity-match. - pub fn decrypt_metadata<C: CryptoProvider>( - &self, - ) -> Result<Vec<u8>, MatchedMetadataDecryptionError<M>> { - self.matched - .fetch_encrypted_metadata() - .map_err(|e| MatchedMetadataDecryptionError::RetrievalFailed(e)) - .and_then(|x| Self::decrypt_metadata_from_fetch::<C>(self, x.as_ref())) - } -} - -/// Data in a V1 advertisement header. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(crate) struct V1Header { - header_byte: u8, -} - -const PROTOCOL_VERSION_LEGACY: u8 = 0; -const PROTOCOL_VERSION_EXTENDED: u8 = 1; - /// Errors that can occur during advertisement deserialization. #[derive(PartialEq)] pub enum AdvDeserializationError { /// The advertisement header could not be parsed - HeaderParseError, + VersionHeaderParseError, /// The advertisement content could not be parsed ParseError { /// Potentially hazardous details about deserialization errors. Read the documentation for @@ -694,7 +127,9 @@ impl Debug for AdvDeserializationError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - AdvDeserializationError::HeaderParseError => write!(f, "HeaderParseError"), + AdvDeserializationError::VersionHeaderParseError => { + write!(f, "VersionHeaderParseError") + } AdvDeserializationError::ParseError { .. } => write!(f, "ParseError"), } } @@ -710,37 +145,24 @@ AdvertisementDeserializeError, /// Deserializing an individual DE from its DE contents failed V0DataElementDeserializeError(DataElementDeserializeError), - /// Must not have any other top level data elements if there is an encrypted identity DE - TooManyTopLevelDataElements, - /// Must not have an identity DE inside an identity DE - InvalidDataElementHierarchy, - /// Must have an identity DE - MissingIdentity, /// Non-identity DE contents must not be empty NoPublicDataElements, } -impl From<AdvDeserializeError> for AdvDeserializationError { - fn from(err: AdvDeserializeError) -> Self { +impl From<legacy::deserialize::AdvDeserializeError> for AdvDeserializationError { + fn from(err: legacy::deserialize::AdvDeserializeError) -> Self { match err { - AdvDeserializeError::AdvertisementDeserializeError => { + legacy::deserialize::AdvDeserializeError::NoDataElements => { + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::NoPublicDataElements, + } + } + legacy::deserialize::AdvDeserializeError::InvalidStructure => { AdvDeserializationError::ParseError { details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError, } } - AdvDeserializeError::TooManyTopLevelDataElements => { - AdvDeserializationError::ParseError { - details_hazmat: - AdvDeserializationErrorDetailsHazmat::TooManyTopLevelDataElements, - } - } - AdvDeserializeError::MissingIdentity => AdvDeserializationError::ParseError { - details_hazmat: AdvDeserializationErrorDetailsHazmat::MissingIdentity, - }, - AdvDeserializeError::NoPublicDataElements => AdvDeserializationError::ParseError { - details_hazmat: AdvDeserializationErrorDetailsHazmat::NoPublicDataElements, - }, } } } @@ -750,15 +172,8 @@ #[derive(Debug, PartialEq, Eq)] pub struct DeLengthOutOfRange; -/// The identity mode for a deserialized plaintext section or advertisement. -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum PlaintextIdentityMode { - /// A "Public Identity" DE was present in the section - Public, +pub(crate) mod private { + /// A marker trait to prevent other crates from implementing traits that + /// are intended to be only implemented internally. + pub trait Sealed {} } - -/// A "public identity" -- a nonspecific "empty identity". -/// -/// Used when serializing V0 advertisements or V1 sections. -#[derive(Default, Debug)] -pub struct PublicIdentity;
diff --git a/nearby/presence/np_adv/src/shared_data.rs b/nearby/presence/np_adv/src/shared_data.rs index b511ed2..c7d241b 100644 --- a/nearby/presence/np_adv/src/shared_data.rs +++ b/nearby/presence/np_adv/src/shared_data.rs
@@ -16,7 +16,7 @@ /// Power in dBm, calibrated as per /// [Eddystone](https://github.com/google/eddystone/tree/master/eddystone-uid#tx-power) -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct TxPower { /// Power in `[-100, 20]` power: i8, @@ -42,7 +42,7 @@ } /// Tx power was out of the valid range `[-100, 20]`. -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct TxPowerOutOfRange; /// MDP's context sync number, used to inform other devices that they have stale context. @@ -73,5 +73,33 @@ } /// Seq num must be in `[0-15]`. -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct ContextSyncSeqNumOutOfRange; + +#[allow(clippy::unwrap_used)] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tx_power_out_of_range() { + assert_eq!(TxPowerOutOfRange, TxPower::try_from(-101).unwrap_err()); + assert_eq!(TxPowerOutOfRange, TxPower::try_from(21).unwrap_err()); + } + + #[test] + fn tx_power_ok() { + assert_eq!(-100, TxPower::try_from(-100).unwrap().power); + assert_eq!(20, TxPower::try_from(20).unwrap().power); + } + + #[test] + fn context_sync_seq_num_out_of_range() { + assert_eq!(ContextSyncSeqNumOutOfRange, ContextSyncSeqNum::try_from(0x10).unwrap_err()); + } + + #[test] + fn context_sync_seq_num_ok() { + assert_eq!(0x0F, ContextSyncSeqNum::try_from(0x0F).unwrap().num); + } +}
diff --git a/nearby/util/pourover_macro_core/src/lib.rs b/nearby/presence/np_adv/src/tests.rs similarity index 83% copy from nearby/util/pourover_macro_core/src/lib.rs copy to nearby/presence/np_adv/src/tests.rs index ae06345..eaa7ced 100644 --- a/nearby/util/pourover_macro_core/src/lib.rs +++ b/nearby/presence/np_adv/src/tests.rs
@@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod jni_method; -pub use jni_method::jni_method; +mod deser_v0_tests; +pub(crate) mod deser_v1_tests;
diff --git a/nearby/presence/np_adv/src/deser_v0_tests.rs b/nearby/presence/np_adv/src/tests/deser_v0_tests.rs similarity index 65% rename from nearby/presence/np_adv/src/deser_v0_tests.rs rename to nearby/presence/np_adv/src/tests/deser_v0_tests.rs index f6643de..b9dc6a8 100644 --- a/nearby/presence/np_adv/src/deser_v0_tests.rs +++ b/nearby/presence/np_adv/src/tests/deser_v0_tests.rs
@@ -18,34 +18,30 @@ extern crate std; +use crate::credential::matched::{EmptyMatchedCredential, HasIdentityMatch, MatchedCredential}; +use crate::credential::MatchableCredential; +use crate::legacy::serialize::UnencryptedEncoder; use crate::{ credential::{ book::{CredentialBook, CredentialBookBuilder}, - v0::{V0DiscoveryCredential, V0}, - EmptyMatchedCredential, MatchableCredential, MatchedCredential, - SimpleBroadcastCryptoMaterial, + v0::{V0BroadcastCredential, V0DiscoveryCredential, V0}, }, - de_type::EncryptedIdentityDataElementType, deserialization_arena, deserialization_arena::DeserializationArena, deserialize_advertisement, legacy::{ - actions::{ActionBits, ActionsDataElement, ToActionElement}, - data_elements::DataElement, - deserialize::PlainDataElement, - serialize::{AdvBuilder, Identity, LdtIdentity}, - ShortMetadataKey, BLE_ADV_SVC_CONTENT_LEN, + data_elements::actions::{ActionBits, ActionsDataElement}, + deserialize::DeserializedDataElement, + serialize::{AdvBuilder, AdvEncoder, LdtEncoder}, + BLE_4_ADV_SVC_MAX_CONTENT_LEN, }, - shared_data::ContextSyncSeqNum, - HasIdentityMatch, PlaintextIdentityMode, PublicIdentity, V0AdvertisementContents, + V0AdvertisementContents, }; use array_view::ArrayView; -use core::marker::PhantomData; use crypto_provider::CryptoProvider; use crypto_provider_default::CryptoProviderImpl; -use ldt_np_adv::LegacySalt; +use ldt_np_adv::{V0IdentityToken, V0Salt, V0_IDENTITY_TOKEN_LEN}; use std::{prelude::rust_2021::*, vec}; -use strum::IntoEnumIterator as _; #[test] fn v0_all_identities_resolvable() { @@ -58,7 +54,7 @@ let creds = identities .iter() .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), + discovery_credential: i.discovery_credential::<CryptoProviderImpl>(), match_data: EmptyMatchedCredential, }) .collect::<Vec<_>>(); @@ -87,7 +83,7 @@ !adv_config.identity.map(|sci| sci.key_seed == i.key_seed).unwrap_or(false) }) .map(|i| MatchableCredential { - discovery_credential: i.discovery_credential(), + discovery_credential: i.discovery_credential::<CryptoProviderImpl>(), match_data: EmptyMatchedCredential, }) .collect::<Vec<_>>(); @@ -146,13 +142,11 @@ match adv_config.identity { None => match adv { V0AdvertisementContents::Plaintext(p) => { - let mut action_bits = ActionBits::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(3).unwrap()); + let action_bits = ActionBits::default(); let de = ActionsDataElement::from(action_bits); - assert_eq!(adv_config.plaintext_mode.unwrap(), p.identity()); assert_eq!( - vec![PlainDataElement::Actions(de)], + vec![DeserializedDataElement::Actions(de)], p.data_elements().collect::<Result<Vec<_>, _>>().unwrap() ) } @@ -160,24 +154,17 @@ }, Some(_) => match adv { V0AdvertisementContents::Decrypted(wmc) => { - assert!(adv_config.plaintext_mode.is_none()); - // different generic type param, so can't re-use the DE from above - let mut action_bits = ActionBits::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(3).unwrap()); + let action_bits = ActionBits::default(); let de = ActionsDataElement::from(action_bits); assert_eq!( - vec![PlainDataElement::Actions(de)], + vec![DeserializedDataElement::Actions(de)], wmc.contents().data_elements().collect::<Result<Vec<_>, _>>().unwrap() ); assert_eq!( - adv_config.identity.unwrap().identity_type, - wmc.contents().identity_type() - ); - assert_eq!( - adv_config.identity.unwrap().legacy_metadata_key, - wmc.contents().metadata_key() + adv_config.identity.unwrap().identity_token, + wmc.contents().identity_token() ); } _ => panic!("should be an encrypted adv"), @@ -203,92 +190,70 @@ /// Populate an advertisement with a randomly chosen identity and a DE fn adv_random_identity<'a, R: rand::Rng>( mut rng: &mut R, - identities: &'a Vec<TestIdentity<CryptoProviderImpl>>, -) -> (ArrayView<u8, { BLE_ADV_SVC_CONTENT_LEN }>, AdvConfig<'a>) { + identities: &'a Vec<TestIdentity>, +) -> (ArrayView<u8, { BLE_4_ADV_SVC_MAX_CONTENT_LEN }>, AdvConfig<'a>) { let identity = identities.choose(&mut rng).unwrap(); if rng.gen_bool(0.5) { - let mut adv_builder = AdvBuilder::new(PublicIdentity); + let mut adv_builder = AdvBuilder::new(UnencryptedEncoder); add_de(&mut adv_builder); - ( - adv_builder.into_advertisement().unwrap(), - AdvConfig::new(None, Some(PlaintextIdentityMode::Public)), - ) + (adv_builder.into_advertisement().unwrap(), AdvConfig::new(None)) } else { - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new( - identity.key_seed, - identity.legacy_metadata_key, - ); - let mut adv_builder = AdvBuilder::new(LdtIdentity::<CryptoProviderImpl>::new( - identity.identity_type, - LegacySalt::from(rng.gen::<[u8; 2]>()), - &broadcast_cm, + let broadcast_cred = V0BroadcastCredential::new(identity.key_seed, identity.identity_token); + let mut adv_builder = AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new( + V0Salt::from(rng.gen::<[u8; 2]>()), + &broadcast_cred, )); add_de(&mut adv_builder); - (adv_builder.into_advertisement().unwrap(), AdvConfig::new(Some(identity), None)) + (adv_builder.into_advertisement().unwrap(), AdvConfig::new(Some(identity))) } } -fn add_de<I>(adv_builder: &mut AdvBuilder<I>) +fn add_de<E>(adv_builder: &mut AdvBuilder<E>) where - I: Identity, - ActionsDataElement<I::Flavor>: DataElement, - ContextSyncSeqNum: ToActionElement<I::Flavor>, + E: AdvEncoder, { - let mut action_bits = ActionBits::default(); - action_bits.set_action(ContextSyncSeqNum::try_from(3).unwrap()); + let action_bits = ActionBits::default(); let de = ActionsDataElement::from(action_bits); adv_builder.add_data_element(de).unwrap(); } -struct TestIdentity<C: CryptoProvider> { - identity_type: EncryptedIdentityDataElementType, +struct TestIdentity { key_seed: [u8; 32], - legacy_metadata_key: ShortMetadataKey, - _marker: PhantomData<C>, + identity_token: V0IdentityToken, } -impl<C: CryptoProvider> TestIdentity<C> { +impl TestIdentity { /// Generate a new identity with random crypto material fn random<R: rand::Rng + rand::CryptoRng>(rng: &mut R) -> Self { Self { - identity_type: *EncryptedIdentityDataElementType::iter() - .collect::<Vec<_>>() - .choose(rng) - .unwrap(), key_seed: rng.gen(), - legacy_metadata_key: ShortMetadataKey(rng.gen()), - _marker: PhantomData, + identity_token: rng.gen::<[u8; V0_IDENTITY_TOKEN_LEN]>().into(), } } /// Returns a discovery-credential using crypto material from this identity - fn discovery_credential(&self) -> V0DiscoveryCredential { - let hkdf = self.hkdf(); + fn discovery_credential<C: CryptoProvider>(&self) -> V0DiscoveryCredential { + let hkdf = self.hkdf::<C>(); V0DiscoveryCredential::new( self.key_seed, - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&self.legacy_metadata_key.0), + hkdf.v0_identity_token_hmac_key().calculate_hmac::<C>(&self.identity_token.bytes()), ) } - fn hkdf(&self) -> np_hkdf::NpKeySeedHkdf<C> { + fn hkdf<C: CryptoProvider>(&self) -> np_hkdf::NpKeySeedHkdf<C> { np_hkdf::NpKeySeedHkdf::new(&self.key_seed) } } struct AdvConfig<'a> { /// `Some` iff an encrypted identity should be used - identity: Option<&'a TestIdentity<CryptoProviderImpl>>, - /// `Some` iff `identity` is `None` - plaintext_mode: Option<PlaintextIdentityMode>, + identity: Option<&'a TestIdentity>, } impl<'a> AdvConfig<'a> { - fn new( - identity: Option<&'a TestIdentity<CryptoProviderImpl>>, - plaintext_mode: Option<PlaintextIdentityMode>, - ) -> Self { - Self { identity, plaintext_mode } + fn new(identity: Option<&'a TestIdentity>) -> Self { + Self { identity } } }
diff --git a/nearby/presence/np_adv/src/tests/deser_v1_tests.rs b/nearby/presence/np_adv/src/tests/deser_v1_tests.rs new file mode 100644 index 0000000..d0865c7 --- /dev/null +++ b/nearby/presence/np_adv/src/tests/deser_v1_tests.rs
@@ -0,0 +1,485 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(clippy::unwrap_used)] + +extern crate std; + +use std::{prelude::rust_2021::*, vec}; + +use rand::{ + distributions::{Distribution, Standard}, + random, + rngs::StdRng, + Rng, SeedableRng as _, +}; + +use array_view::ArrayView; +use crypto_provider::{ed25519, CryptoRng}; +use crypto_provider_default::CryptoProviderImpl; +use np_hkdf::v1_salt::ExtendedV1Salt; + +use crate::{ + credential::{book::*, matched::*, v0::*, v1::*, *}, + extended::{ + data_elements::GenericDataElement, + deserialize::{data_element::DataElement, section::intermediate::PlaintextSection, *}, + salt::MultiSalt, + serialize::*, + *, + }, + *, +}; + +mod happy_path; + +mod error_condition; + +impl<'adv, M: MatchedCredential> V1DeserializedSection<'adv, M> { + fn as_plaintext_section(&self) -> &PlaintextSection { + match self { + V1DeserializedSection::Plaintext(c) => c, + V1DeserializedSection::Decrypted(_) => { + panic!("Casting into invalid enum variant") + } + } + } + + fn as_ciphertext_section(&self) -> &WithMatchedCredential<M, DecryptedSection<'adv>> { + match self { + V1DeserializedSection::Plaintext(_) => panic!("Casting into invalid enum variant"), + V1DeserializedSection::Decrypted(wmc) => wmc, + } + } +} + +fn assert_section_equals( + section_config: &SectionConfig, + section: &V1DeserializedSection< + ReferencedMatchedCredential<MetadataMatchedCredential<Vec<u8>>>, + >, +) { + match §ion_config.identity_kind { + IdentityKind::Plaintext => { + let plaintext_section = section.as_plaintext_section(); + assert_eq!( + section_config.data_elements, + plaintext_section + .iter_data_elements() + .map(|de| (&de.unwrap()).into()) + .collect::<Vec<_>>() + ) + } + IdentityKind::Encrypted { verification_mode, identity } => { + let enc_section = section.as_ciphertext_section(); + + let decrypted_metadata = enc_section.decrypt_metadata::<CryptoProviderImpl>().unwrap(); + assert_eq!(&identity.plaintext_metadata, &decrypted_metadata); + + let expected_contents = + section_config.data_elements.clone().iter().fold(Vec::new(), |mut buf, de| { + buf.extend_from_slice(de.de_header().serialize().as_slice()); + de.write_de_contents(&mut buf).unwrap(); + buf + }); + let contents = enc_section.contents(); + assert_eq!(&expected_contents, contents.plaintext()); + + assert_eq!( + section_config.data_elements, + contents + .iter_data_elements() + .map(|de| (&de.unwrap()).into()) + .collect::<Vec<GenericDataElement>>() + ); + assert_eq!(&identity.identity_token, enc_section.contents().identity_token()); + assert_eq!(verification_mode, &enc_section.contents().verification_mode()); + } + } +} + +fn deser_v1_error<'a, B, P>( + arena: DeserializationArena<'a>, + adv: &'a [u8], + cred_book: &'a B, +) -> AdvDeserializationError +where + B: CredentialBook<'a>, + P: CryptoProvider, +{ + let v1_contents = match crate::deserialize_advertisement::<_, P>(arena, adv, cred_book) { + Err(e) => e, + _ => panic!("Expecting an error!"), + }; + v1_contents +} + +fn deser_v1<'adv, B, P>( + arena: DeserializationArena<'adv>, + adv: &'adv [u8], + cred_book: &'adv B, +) -> V1AdvertisementContents<'adv, B::Matched> +where + B: CredentialBook<'adv>, + P: CryptoProvider, +{ + crate::deserialize_advertisement::<_, P>(arena, adv, cred_book) + .expect("Should be a valid advertisement") + .into_v1() + .expect("Should be V1") +} + +fn build_empty_cred_book() -> PrecalculatedOwnedCredentialBook<EmptyMatchedCredential> { + PrecalculatedOwnedCredentialBook::new( + PrecalculatedOwnedCredentialSource::<V0, EmptyMatchedCredential>::new::<CryptoProviderImpl>( + Vec::new(), + ), + PrecalculatedOwnedCredentialSource::<V1, EmptyMatchedCredential>::new::<CryptoProviderImpl>( + Vec::new(), + ), + ) +} + +/// Populate a random number of sections with randomly chosen identities and random DEs +fn fill_plaintext_adv<'a, R: rand::Rng>( + rng: &mut R, + adv_builder: &mut AdvBuilder, +) -> SectionConfig<'a> { + adv_builder + .section_builder(UnencryptedSectionEncoder) + .map(|mut s| { + let mut sink = Vec::new(); + // plaintext sections cannot be empty so we need to be sure at least 1 DE is generated + let (_, des) = fill_section_random_des::<_, _, 1>(rng, &mut sink, &mut s); + s.add_to_advertisement::<CryptoProviderImpl>(); + SectionConfig::new(IdentityKind::Plaintext, des) + }) + .unwrap() +} + +impl Distribution<VerificationMode> for Standard { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> VerificationMode { + match rng.gen_range(0..=2) { + 0 => VerificationMode::Signature, + _ => VerificationMode::Mic, + } + } +} + +pub(crate) fn add_sig_rand_salt_to_adv<'a, R: rand::Rng, C: CryptoProvider, const M: usize>( + rng: &mut R, + identity: &'a TestIdentity, + adv_builder: &mut AdvBuilder, +) -> Result<SectionConfig<'a>, AddSectionError> { + let salt: ExtendedV1Salt = rng.gen::<[u8; 16]>().into(); + add_sig_with_salt_to_adv::<_, C, M>(rng, identity, adv_builder, salt.into()) +} + +fn add_sig_with_salt_to_adv<'a, R: rand::Rng, C: CryptoProvider, const M: usize>( + rng: &mut R, + identity: &'a crate::tests::deser_v1_tests::TestIdentity, + adv_builder: &mut AdvBuilder, + salt: MultiSalt, +) -> Result<crate::tests::deser_v1_tests::SectionConfig<'a>, AddSectionError> { + let broadcast_cred = identity.broadcast_credential(); + let salt = match salt { + MultiSalt::Short(_) => { + panic!("Invalid salt type for signature encrpted adv") + } + MultiSalt::Extended(e) => e, + }; + adv_builder.section_builder(SignedEncryptedSectionEncoder::new::<C>(salt, &broadcast_cred)).map( + |mut s| { + let mut sink = Vec::new(); + let (_, des) = fill_section_random_des::<_, _, M>(rng, &mut sink, &mut s); + s.add_to_advertisement::<C>(); + SectionConfig::new( + IdentityKind::Encrypted { + verification_mode: VerificationMode::Signature, + identity, + }, + des, + ) + }, + ) +} + +pub(crate) fn add_mic_rand_salt_to_adv<'a, R: rand::Rng, C: CryptoProvider, const M: usize>( + rng: &mut R, + identity: &'a TestIdentity, + adv_builder: &mut AdvBuilder, +) -> Result<SectionConfig<'a>, AddSectionError> { + let salt = if rng.gen_bool(0.5) { + MultiSalt::Short(rng.gen::<[u8; 2]>().into()) + } else { + MultiSalt::Extended(rng.gen::<[u8; 16]>().into()) + }; + + add_mic_with_salt_to_adv::<_, C, M>(rng, identity, adv_builder, salt) +} + +pub(crate) fn add_mic_with_salt_to_adv<'a, R: rand::Rng, C: CryptoProvider, const M: usize>( + rng: &mut R, + identity: &'a TestIdentity, + adv_builder: &mut AdvBuilder, + salt: MultiSalt, +) -> Result<crate::tests::deser_v1_tests::SectionConfig<'a>, AddSectionError> { + let broadcast_cred = identity.broadcast_credential(); + adv_builder + .section_builder(MicEncryptedSectionEncoder::<_>::new_with_salt::<C>(salt, &broadcast_cred)) + .map(|mut s| { + let mut sink = Vec::new(); + let (_, des) = fill_section_random_des::<_, _, M>(rng, &mut sink, &mut s); + s.add_to_advertisement::<C>(); + SectionConfig::new( + IdentityKind::Encrypted { verification_mode: VerificationMode::Mic, identity }, + des, + ) + }) +} + +/// Populate a random number of sections with randomly chosen identities and random DEs +fn fill_with_encrypted_sections<'a, R: rand::Rng, C: CryptoProvider>( + mut rng: &mut R, + identities: &'a TestIdentities, + adv_builder: &mut AdvBuilder, +) -> Vec<SectionConfig<'a>> { + let mut expected = Vec::new(); + for _ in 0..rng.gen_range(1..=NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT) { + let identity = identities.pick_random_identity(&mut rng); + let mode: VerificationMode = random(); + let res = match mode { + VerificationMode::Signature => { + add_sig_rand_salt_to_adv::<_, C, 0>(&mut rng, identity, adv_builder) + } + VerificationMode::Mic => { + add_mic_rand_salt_to_adv::<_, C, 0>(&mut rng, identity, adv_builder) + } + }; + match res { + Ok(tuple) => expected.push(tuple), + Err(_) => { + // couldn't fit that section; maybe another smaller section will fit + continue; + } + } + } + expected +} + +#[derive(Clone)] +pub(crate) struct TestIdentity { + key_seed: [u8; 32], + identity_token: V1IdentityToken, + private_key: ed25519::PrivateKey, + plaintext_metadata: Vec<u8>, +} + +impl TestIdentity { + /// Generate a new identity with random crypto material + fn random<R: rand::Rng, C: CryptoProvider>(rng: &mut R) -> Self { + Self { + key_seed: rng.gen(), + identity_token: rng.gen(), + private_key: ed25519::PrivateKey::generate::<C::Ed25519>(), + // varying length vec of random bytes + plaintext_metadata: (0..rng.gen_range(50..200)).map(|_| rng.gen()).collect(), + } + } + /// Returns a (simple, signed) broadcast credential using crypto material from this identity + fn broadcast_credential(&self) -> V1BroadcastCredential { + V1BroadcastCredential::new(self.key_seed, self.identity_token, self.private_key.clone()) + } + /// Returns a discovery credential using crypto material from this identity + fn discovery_credential<C: CryptoProvider>(&self) -> V1DiscoveryCredential { + self.broadcast_credential().derive_discovery_credential::<C>() + } +} + +pub(crate) struct SectionConfig<'a> { + identity_kind: IdentityKind<'a>, + data_elements: Vec<GenericDataElement>, +} + +pub(crate) enum IdentityKind<'a> { + Plaintext, + Encrypted { verification_mode: VerificationMode, identity: &'a TestIdentity }, +} + +impl<'a> SectionConfig<'a> { + pub fn new(identity_kind: IdentityKind<'a>, data_elements: Vec<GenericDataElement>) -> Self { + Self { identity_kind, data_elements } + } +} + +/// Returns the DEs created in both deserialized form ([DataElement]) and +/// input form ([GenericDataElement]) where `M` is the minimum number of DE's +/// generated +fn fill_section_random_des<'adv, R: rand::Rng, I: SectionEncoder, const M: usize>( + mut rng: &mut R, + sink: &'adv mut Vec<u8>, + section_builder: &mut SectionBuilder<&mut AdvBuilder, I>, +) -> (Vec<DataElement<'adv>>, Vec<GenericDataElement>) { + let mut expected_des = vec![]; + let mut orig_des = vec![]; + let mut de_ranges = vec![]; + + for _ in 0..rng.gen_range(M..=5) { + let de = random_de::<MAX_DE_LEN, _>(&mut rng); + + let de_clone = de.clone(); + if section_builder.add_de(|_| de_clone).is_err() { + break; + } + + let orig_len = sink.len(); + de.write_de_contents(sink).unwrap(); + let contents_len = sink.len() - orig_len; + de_ranges.push(orig_len..orig_len + contents_len); + orig_des.push(de); + } + + for (index, (de, range)) in orig_des.iter().zip(de_ranges).enumerate() { + expected_des.push(DataElement::new( + u8::try_from(index).unwrap().into(), + de.de_header().de_type, + &sink[range], + )); + } + (expected_des, orig_des) +} + +/// generates a random DE, where `N` is the max length size of the DE +fn random_de<const N: usize, R: rand::Rng>(rng: &mut R) -> GenericDataElement { + let mut array = [0_u8; MAX_DE_LEN]; + rng.fill(&mut array[..]); + let data: ArrayView<u8, MAX_DE_LEN> = + ArrayView::try_from_array(array, rng.gen_range(0..=MAX_DE_LEN)).unwrap(); + // skip the first few DEs that Google uses + GenericDataElement::try_from(rng.gen_range(0_u32..1000).into(), data.as_slice()).unwrap() +} + +#[derive(Clone)] +pub(crate) struct TestIdentities(pub(crate) Vec<TestIdentity>); + +impl TestIdentities { + pub(crate) fn generate<const N: usize, R: rand::Rng, C: CryptoProvider>( + rng: &mut R, + ) -> TestIdentities { + TestIdentities((0..N).map(|_| TestIdentity::random::<_, C>(rng)).collect::<Vec<_>>()) + } + + fn pick_random_identity<R: rand::Rng>(&self, rng: &mut R) -> &TestIdentity { + let chosen_index = rng.gen_range(0..self.0.len()); + &self.0[chosen_index] + } + + pub(crate) fn build_cred_book<C: CryptoProvider>( + &self, + ) -> PrecalculatedOwnedCredentialBook<MetadataMatchedCredential<Vec<u8>>> { + let creds = self + .0 + .iter() + .map(|identity| { + let match_data = MetadataMatchedCredential::<Vec<u8>>::encrypt_from_plaintext::< + V1, + CryptoProviderImpl, + >( + &np_hkdf::NpKeySeedHkdf::new(&identity.key_seed), + identity.identity_token, + &identity.plaintext_metadata, + ); + let discovery_credential = identity.discovery_credential::<C>(); + MatchableCredential { discovery_credential, match_data } + }) + .collect::<Vec<_>>(); + let cred_source = PrecalculatedOwnedCredentialSource::new::<CryptoProviderImpl>(creds); + PrecalculatedOwnedCredentialBook::new( + PrecalculatedOwnedCredentialSource::<V0, MetadataMatchedCredential<Vec<u8>>>::new::< + CryptoProviderImpl, + >(Vec::new()), + cred_source, + ) + } +} + +fn deserialize_rand_identities_finds_correct_one<E, F>( + build_encoder: F, + expected_mode: VerificationMode, +) where + E: SectionEncoder, + F: Fn(&mut <CryptoProviderImpl as CryptoProvider>::CryptoRng, &V1BroadcastCredential) -> E, +{ + let mut rng = StdRng::from_entropy(); + let mut crypto_rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); + + for _ in 0..100 { + let identities = TestIdentities::generate::<100, _, CryptoProviderImpl>(&mut rng); + let identity = identities.pick_random_identity(&mut rng); + let book = identities.build_cred_book::<CryptoProviderImpl>(); + + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let broadcast_cm = identity.broadcast_credential(); + let mut section_builder = + adv_builder.section_builder(build_encoder(&mut crypto_rng, &broadcast_cm)).unwrap(); + + let mut expected_de_data = vec![]; + let (expected_des, orig_des) = fill_section_random_des::<_, _, 0>( + &mut rng, + &mut expected_de_data, + &mut section_builder, + ); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); + + let section_config = SectionConfig::new( + IdentityKind::Encrypted { verification_mode: expected_mode, identity }, + orig_des.clone(), + ); + + let adv = adv_builder.into_advertisement(); + + let arena = deserialization_arena!(); + let decrypted_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &book); + assert_eq!(0, decrypted_contents.invalid_sections_count()); + let sections = decrypted_contents.into_sections(); + assert_eq!(1, sections.len()); + + assert_section_equals(§ion_config, §ions[0]); + + // verify data elements match original after collecting them from the section + let data_elements = + sections[0].as_ciphertext_section().contents().collect_data_elements().unwrap(); + assert_eq!(expected_des, data_elements); + } +} + +fn add_plaintext_section<R: rand::Rng>( + rng: &mut R, + builder: &mut AdvBuilder, +) -> Result<(), AddSectionError> { + builder.section_builder(UnencryptedSectionEncoder).map(|mut sb| { + // use an upper bound on the De size to leave room for another section + sb.add_de(|_| random_de::<20, _>(rng)).unwrap(); + sb.add_to_advertisement::<CryptoProviderImpl>(); + }) +} + +fn append_mock_encrypted_section(adv: &mut Vec<u8>) { + adv.push(0b0000_0001u8); // format + adv.extend_from_slice(&[0xAA; 2]); // short salt + adv.extend_from_slice(&[0xBB; 16]); // identity token + adv.push(3); // payload length + adv.extend_from_slice(&[0xCC; 3]); // payload contents +}
diff --git a/nearby/presence/np_adv/src/tests/deser_v1_tests/error_condition.rs b/nearby/presence/np_adv/src/tests/deser_v1_tests/error_condition.rs new file mode 100644 index 0000000..9f91dbd --- /dev/null +++ b/nearby/presence/np_adv/src/tests/deser_v1_tests/error_condition.rs
@@ -0,0 +1,257 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::deserialization_arena; +use rand::SeedableRng; + +#[test] +fn v1_multiple_plaintext_sections() { + let mut rng = StdRng::from_entropy(); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + add_plaintext_section(&mut rng, &mut adv_builder).unwrap(); + + // append an extra plaintext section + let adv = [ + adv_builder.into_advertisement().as_slice(), + &[ + 0x00, // format unencrypted + 0x03, // section len + ], + &[0xDD; 3], // 3 bytes of de contents + ] + .concat(); + + let arena = deserialization_arena!(); + let cred_book = build_empty_cred_book(); + let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, &adv, &cred_book); + assert_eq!( + v1_error, + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError + } + ); +} + +#[test] +fn v1_plaintext_empty_contents() { + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + let sb = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); + sb.add_to_advertisement::<CryptoProviderImpl>(); + let adv = adv_builder.into_advertisement(); + + let arena = deserialization_arena!(); + let cred_book = build_empty_cred_book(); + let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!( + v1_error, + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError + } + ); +} + +#[test] +fn v1_adv_no_sections() { + let mut rng = StdRng::from_entropy(); + let identities = TestIdentities::generate::<5, _, CryptoProviderImpl>(&mut rng); + let adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let adv = adv_builder.into_advertisement(); + + let arena = deserialization_arena!(); + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + + let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!( + v1_error, + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError + } + ); +} + +#[test] +fn v1_no_creds_available_ciphertext() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let identities = TestIdentities::generate::<100, _, CryptoProviderImpl>(&mut rng); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let section_configs = fill_with_encrypted_sections::<_, CryptoProviderImpl>( + &mut rng, + &identities, + &mut adv_builder, + ); + let adv = adv_builder.into_advertisement(); + + let cred_book = build_empty_cred_book(); + let arena = deserialization_arena!(); + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!(section_configs.len(), v1_contents.invalid_sections_count()); + assert_eq!(0, v1_contents.sections().len()); + } +} + +#[test] +fn v1_only_non_matching_identities_available_ciphertext() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let mut identities = TestIdentities::generate::<100, _, CryptoProviderImpl>(&mut rng); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let cloned_identities = identities.clone(); + let section_configs = fill_with_encrypted_sections::<_, CryptoProviderImpl>( + &mut rng, + &cloned_identities, + &mut adv_builder, + ); + let adv = adv_builder.into_advertisement(); + + // only retain identities in the book that haven't been used in the constructed adv sections + identities.0.retain(|identity| { + !section_configs.iter().any(|sc| match &sc.identity_kind { + IdentityKind::Plaintext => panic!("There are no plaintext sections"), + IdentityKind::Encrypted { identity: section_identity, verification_mode: _ } => { + identity.key_seed == section_identity.key_seed + } + }) + }); + + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + let arena = deserialization_arena!(); + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!(section_configs.len(), v1_contents.invalid_sections_count()); + assert_eq!(0, v1_contents.sections().len()); + } +} + +// TODO: this may be valid in future changes and would need to be updated +#[test] +fn v1_plaintext_then_encrypted_sections() { + let mut rng = StdRng::from_entropy(); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + let identities = TestIdentities::generate::<5, _, CryptoProviderImpl>(&mut rng); + + add_plaintext_section(&mut rng, &mut adv_builder).unwrap(); + let mut adv = adv_builder.into_advertisement().as_slice().to_vec(); + append_mock_encrypted_section(&mut adv); + + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + let arena = deserialization_arena!(); + + let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!( + v1_error, + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError + } + ); +} + +#[test] +fn v1_encrypted_then_plaintext_sections() { + let mut rng = StdRng::from_entropy(); + let mut builder = AdvBuilder::new(AdvertisementType::Encrypted); + let identities = TestIdentities::generate::<1, _, CryptoProviderImpl>(&mut rng); + + let _ = add_mic_rand_salt_to_adv::<_, CryptoProviderImpl, 0>( + &mut rng, + &identities.0[0], + &mut builder, + ) + .unwrap(); + let mut adv = builder.into_advertisement().as_slice().to_vec(); + + // Append plaintext section + adv.push(V1_ENCODING_UNENCRYPTED); //Header + adv.push(3); // section len + adv.extend_from_slice(&[0xFF; 3]); //section contents + + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + let arena = deserialization_arena!(); + + let v1_error = deser_v1_error::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!( + v1_error, + AdvDeserializationError::ParseError { + details_hazmat: AdvDeserializationErrorDetailsHazmat::AdvertisementDeserializeError + } + ); +} + +#[test] +fn v1_encrypted_matching_identity_but_mic_mismatch() { + for _ in 0..100 { + v1_deserialize_error_test_tampered_adv( + add_mic_rand_salt_to_adv::<StdRng, CryptoProviderImpl, 0>, + |adv| { + // mangle the last 2 bytes of the suffix to invalidate the advertisement. + // the identity should still correctly match + let adv_len = adv.len(); + adv[adv_len - 2..].copy_from_slice(&[0xFF; 2]); + }, + ) + } +} + +#[test] +fn v1_encrypted_matching_identity_but_sig_mismatch() { + v1_deserialize_error_test_tampered_adv( + add_sig_rand_salt_to_adv::<StdRng, CryptoProviderImpl, 0>, + |adv| { + // mangle the last 2 bytes of the suffix to invalidate the advertisement. + // the identity should still correctly match + let adv_len = adv.len(); + adv[adv_len - 2..].copy_from_slice(&[0xFF; 2]); + }, + ) +} + +#[test] +fn v1_encrypted_matching_identity_missing_signature() { + v1_deserialize_error_test_tampered_adv( + add_sig_rand_salt_to_adv::<StdRng, CryptoProviderImpl, 0>, + |adv| { + // only keep the last 63 byte bytes after the len, which is too short to fit a signature + // 1 byte header + 1 byte format + 16 byte salt + 16 byte token + 1 byte len + 63 bytes of contents + adv.truncate(1 + 1 + 16 + 16 + 1 + 63); + // modify the length byte to account for this otherwise this will fail to parse at all + // 1 byte header + 1 byte format + 16 byte salt + 16 byte token + let len_byte_index = 1 + 1 + 16 + 16; + adv[len_byte_index] = 63; + }, + ) +} + +fn v1_deserialize_error_test_tampered_adv( + add_to_adv: impl for<'a> Fn( + &mut StdRng, + &'a TestIdentity, + &mut AdvBuilder, + ) -> Result<SectionConfig<'a>, AddSectionError>, + mangle_adv: impl Fn(&mut Vec<u8>), +) { + let mut rng = StdRng::from_entropy(); + let mut builder = AdvBuilder::new(AdvertisementType::Encrypted); + let identities = TestIdentities::generate::<1, _, CryptoProviderImpl>(&mut rng); + + let _ = add_to_adv(&mut rng, &identities.0[0], &mut builder); + let mut adv = builder.into_advertisement().as_slice().to_vec(); + + mangle_adv(&mut adv); + + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + let arena = deserialization_arena!(); + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!(1, v1_contents.invalid_sections_count()); + assert_eq!(0, v1_contents.sections().len()); +}
diff --git a/nearby/presence/np_adv/src/tests/deser_v1_tests/happy_path.rs b/nearby/presence/np_adv/src/tests/deser_v1_tests/happy_path.rs new file mode 100644 index 0000000..2171bd6 --- /dev/null +++ b/nearby/presence/np_adv/src/tests/deser_v1_tests/happy_path.rs
@@ -0,0 +1,227 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate std; + +use super::*; +use crate::{deserialization_arena, extended::salt::*}; +use rand::SeedableRng; + +#[test] +fn deserialize_rand_identities_single_section_finds_correct_one_mic_short_salt() { + deserialize_rand_identities_finds_correct_one( + |_rng, bc| { + let salt = ShortV1Salt::from([0x3; 2]); + MicEncryptedSectionEncoder::<_>::new_with_salt::<CryptoProviderImpl>(salt, bc) + }, + VerificationMode::Mic, + ) +} + +#[test] +fn deserialize_rand_identities_single_section_finds_correct_one_mic_extended_salt() { + deserialize_rand_identities_finds_correct_one( + |rng, bc| { + let salt: ExtendedV1Salt = rng.gen(); + MicEncryptedSectionEncoder::<_>::new_with_salt::<CryptoProviderImpl>(salt, bc) + }, + VerificationMode::Mic, + ) +} + +#[test] +fn deserialize_rand_identities_single_section_finds_correct_one_signed() { + deserialize_rand_identities_finds_correct_one( + SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>, + VerificationMode::Signature, + ) +} + +#[test] +fn v1_plaintext() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); + let section_config = fill_plaintext_adv(&mut rng, &mut adv_builder); + let adv = adv_builder.into_advertisement(); + let arena = deserialization_arena!(); + let cred_book = + CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>(&[], &[]); + + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!(0, v1_contents.invalid_sections_count()); + assert_eq!(1, v1_contents.sections().len()); + let sections = v1_contents.into_sections(); + assert_section_equals(§ion_config, §ions[0]); + } +} + +#[test] +fn v1_all_identities_resolvable_ciphertext() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let identities = TestIdentities::generate::<100, _, CryptoProviderImpl>(&mut rng); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let section_configs = fill_with_encrypted_sections::<_, CryptoProviderImpl>( + &mut rng, + &identities, + &mut adv_builder, + ); + let adv = adv_builder.into_advertisement(); + + let arena = deserialization_arena!(); + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + assert_eq!(0, v1_contents.invalid_sections_count()); + assert_eq!(section_configs.len(), v1_contents.sections().len()); + for (section_config, section) in section_configs.iter().zip(v1_contents.sections()) { + assert_section_equals(section_config, section); + } + } +} + +#[test] +fn v1_only_some_matching_identities_available_ciphertext() { + let mut rng = StdRng::from_entropy(); + for _ in 0..100 { + let mut identities = TestIdentities::generate::<100, _, CryptoProviderImpl>(&mut rng); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + let cloned_identities = identities.clone(); + let section_configs = fill_with_encrypted_sections::<_, CryptoProviderImpl>( + &mut rng, + &cloned_identities, + &mut adv_builder, + ); + let adv = adv_builder.into_advertisement(); + + // Hopefully one day we can use extract_if instead: https://github.com/rust-lang/rust/issues/43244 + let mut removed = vec![]; + // Remove some of the identities which have been used to build the adv + identities.0.retain(|identity| { + let res = !section_configs.iter().any(|sc| match &sc.identity_kind { + IdentityKind::Plaintext => panic!("There are no plaintext sections"), + IdentityKind::Encrypted { identity: section_identity, verification_mode: _ } => { + // only remove half the identities that were used + (identity.key_seed == section_identity.key_seed) && rng.gen() + } + }); + if !(res) { + removed.push(identity.clone()); + } + res + }); + + // Need to account for how many sections were affected since the same identity could be used + // to encode multiple different sections + let affected_sections = section_configs + .iter() + .filter(|sc| match sc.identity_kind { + IdentityKind::Plaintext => { + panic!("There are no plaintext sections") + } + IdentityKind::Encrypted { identity: si, verification_mode: _ } => { + removed.iter().any(|i| i.key_seed == si.key_seed) + } + }) + .count(); + + let arena = deserialization_arena!(); + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + let v1_contents = deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book); + + assert_eq!(affected_sections, v1_contents.invalid_sections_count()); + assert_eq!(section_configs.len() - affected_sections, v1_contents.sections().len()); + + for (section_config, section) in section_configs + .iter() + // skip sections w/ removed identities + .filter(|sc| match sc.identity_kind { + IdentityKind::Plaintext => { + panic!("There are no plaintext sections") + } + IdentityKind::Encrypted { identity: si, verification_mode: _ } => { + !removed.iter().any(|i| i.key_seed == si.key_seed) + } + }) + .zip(v1_contents.sections()) + { + assert_section_equals(section_config, section); + } + } +} + +#[test] +fn v1_decrypted_mic_short_salt_matches() { + let mut rng = StdRng::from_entropy(); + let salt = MultiSalt::Short(rng.gen::<[u8; 2]>().into()); + v1_decrypted_adv_salt_matches( + &mut rng, + salt, + add_mic_with_salt_to_adv::<_, CryptoProviderImpl, 0>, + ); +} + +#[test] +fn v1_decrypted_mic_extended_salt_matches() { + let mut rng = StdRng::from_entropy(); + let salt = MultiSalt::Extended(rng.gen::<[u8; 16]>().into()); + v1_decrypted_adv_salt_matches( + &mut rng, + salt, + add_mic_with_salt_to_adv::<_, CryptoProviderImpl, 0>, + ); +} + +#[test] +fn v1_decrypted_sig_extended_salt_matches() { + let mut rng = StdRng::from_entropy(); + let salt = MultiSalt::Extended(rng.gen::<[u8; 16]>().into()); + v1_decrypted_adv_salt_matches( + &mut rng, + salt, + add_sig_with_salt_to_adv::<_, CryptoProviderImpl, 0>, + ); +} + +fn v1_decrypted_adv_salt_matches( + rng: &mut StdRng, + salt: MultiSalt, + add_to_adv: impl for<'a> Fn( + &mut StdRng, + &'a TestIdentity, + &mut AdvBuilder, + MultiSalt, + ) -> Result<SectionConfig<'a>, AddSectionError>, +) { + let identities = TestIdentities::generate::<1, _, CryptoProviderImpl>(rng); + let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); + + let _ = add_to_adv(rng, &identities.0[0], &mut adv_builder, salt); + + let adv = adv_builder.into_advertisement(); + let arena = deserialization_arena!(); + let cred_book = identities.build_cred_book::<CryptoProviderImpl>(); + + let sections = + deser_v1::<_, CryptoProviderImpl>(arena, adv.as_slice(), &cred_book).into_sections(); + let section = §ions[0]; + let decrypted = match section { + V1DeserializedSection::Plaintext(_) => { + panic!("section is encrypted") + } + V1DeserializedSection::Decrypted(d) => d, + }; + assert_eq!(salt, *decrypted.contents().salt()) +}
diff --git a/nearby/presence/np_adv/tests/examples_v0.rs b/nearby/presence/np_adv/tests/examples_v0.rs index f7b7d5e..b00fd61 100644 --- a/nearby/presence/np_adv/tests/examples_v0.rs +++ b/nearby/presence/np_adv/tests/examples_v0.rs
@@ -15,21 +15,25 @@ use crypto_provider_default::CryptoProviderImpl; use ldt_np_adv::*; -use np_adv::legacy::data_elements::TxPowerDataElement; +use np_adv::credential::matched::{ + EmptyMatchedCredential, HasIdentityMatch, MetadataMatchedCredential, +}; +use np_adv::legacy::serialize::{AdvBuilder, LdtEncoder}; use np_adv::{ credential::{ book::CredentialBookBuilder, - v0::{V0DiscoveryCredential, V0}, - EmptyMatchedCredential, MatchableCredential, MetadataMatchedCredential, - SimpleBroadcastCryptoMaterial, + v0::{V0BroadcastCredential, V0DiscoveryCredential, V0}, + MatchableCredential, }, - de_type::*, - legacy::{deserialize::*, ShortMetadataKey}, + legacy::{ + data_elements::tx_power::TxPowerDataElement, deserialize::*, V0AdvertisementContents, + }, shared_data::*, *, }; use serde::{Deserialize, Serialize}; +#[rustfmt::skip] #[test] fn v0_deser_plaintext() { let cred_book = CredentialBookBuilder::<EmptyMatchedCredential>::build_cached_slice_book::< @@ -41,21 +45,19 @@ let adv = deserialize_advertisement::<_, CryptoProviderImpl>( arena, &[ - 0x00, // adv header - 0x03, // public identity + 0x00, // version header 0x15, 0x03, // Length 1 Tx Power DE with value 3 ], &cred_book, ) - .expect("Should be a valid advertisement") - .into_v0() - .expect("Should be V0"); + .expect("Should be a valid advertisement") + .into_v0() + .expect("Should be V0"); match adv { V0AdvertisementContents::Plaintext(p) => { - assert_eq!(PlaintextIdentityMode::Public, p.identity()); assert_eq!( - vec![PlainDataElement::TxPower(TxPowerDataElement::from( + vec![DeserializedDataElement::TxPower(TxPowerDataElement::from( TxPower::try_from(3).unwrap() ))], p.data_elements().collect::<Result<Vec<_>, _>>().unwrap() @@ -84,42 +86,45 @@ } } +#[rustfmt::skip] #[test] fn v0_deser_ciphertext() { // These are kept fixed in this example for reproducibility. // In practice, these should instead be derived from a cryptographically-secure // random number generator. let key_seed = [0x11_u8; 32]; - let metadata_key: [u8; NP_LEGACY_METADATA_KEY_LEN] = [0x33; NP_LEGACY_METADATA_KEY_LEN]; - let metadata_key = ShortMetadataKey(metadata_key); + let identity_token = V0IdentityToken::from([0x33; V0_IDENTITY_TOKEN_LEN]); - let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); + let broadcast_cred = V0BroadcastCredential::new(key_seed, identity_token); let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let metadata_key_hmac: [u8; 32] = - hkdf.legacy_metadata_key_hmac_key().calculate_hmac(&metadata_key.0); + let identity_token_hmac: [u8; 32] = + hkdf.v0_identity_token_hmac_key().calculate_hmac::<CryptoProviderImpl>(&identity_token.bytes()); // Serialize and encrypt some identity metadata (sender-side) let sender_metadata = IdentityMetadata { name: "Alice".to_string(), email: "alice@gmail.com".to_string() }; let sender_metadata_bytes = sender_metadata.to_bytes(); - let encrypted_sender_metadata = MetadataMatchedCredential::<Vec<u8>>::encrypt_from_plaintext::< - _, - _, - CryptoProviderImpl, - >(&broadcast_cm, &sender_metadata_bytes); + let encrypted_sender_metadata = MetadataMatchedCredential::<Vec<u8>>:: + encrypt_from_plaintext::<V0, CryptoProviderImpl>(&hkdf, + identity_token, + &sender_metadata_bytes); // output of building a packet using AdvBuilder let adv = &[ - 0x00, // adv header - 0x21, // private DE w/ a 2 byte payload + 0x04, // version header 0x22, 0x22, // salt // ciphertext for metadata key & txpower DE - 0x85, 0xBF, 0xA8, 0x83, 0x58, 0x7C, 0x50, 0xCF, 0x98, 0x38, 0xA7, 0x8A, 0xC0, 0x1C, 0x96, - 0xF9, + 0xD8, 0x22, 0x12, 0xEF, 0x16, 0xDB, 0xF8, 0x72, 0xF2, 0xA3, 0xA7, + 0xC0, 0xFA, 0x52, 0x48, 0xEC ]; - let discovery_credential = V0DiscoveryCredential::new(key_seed, metadata_key_hmac); + // make sure output hasn't changed + let mut builder = AdvBuilder::new(LdtEncoder::<CryptoProviderImpl>::new([0x22; 2].into(), &broadcast_cred)); + builder.add_data_element(TxPowerDataElement::from(TxPower::try_from(3).unwrap())).unwrap(); + assert_eq!(adv, builder.into_advertisement().unwrap().as_slice()); + + let discovery_credential = V0DiscoveryCredential::new(key_seed, identity_token_hmac); let credentials: [MatchableCredential<V0, MetadataMatchedCredential<_>>; 1] = [MatchableCredential { discovery_credential, match_data: encrypted_sender_metadata }]; @@ -134,12 +139,12 @@ adv, &cred_book, ) - .expect("Should be a valid advertisement") - .into_v0() - .expect("Should be V0") + .expect("Should be a valid advertisement") + .into_v0() + .expect("Should be V0") { V0AdvertisementContents::Decrypted(c) => c, - _ => panic!("this examples is ciphertext"), + _ => panic!("this example is ciphertext"), }; let decrypted_metadata_bytes = matched @@ -152,12 +157,10 @@ let decrypted = matched.contents(); - assert_eq!(EncryptedIdentityDataElementType::Private, decrypted.identity_type()); - - assert_eq!(metadata_key, decrypted.metadata_key()); + assert_eq!(identity_token, decrypted.identity_token()); assert_eq!( - vec![PlainDataElement::TxPower(TxPowerDataElement::from(TxPower::try_from(3).unwrap())),], + vec![DeserializedDataElement::TxPower(TxPowerDataElement::from(TxPower::try_from(3).unwrap())),], decrypted.data_elements().collect::<Result<Vec<_>, _>>().unwrap(), ); }
diff --git a/nearby/presence/np_adv/tests/examples_v1.rs b/nearby/presence/np_adv/tests/examples_v1.rs index f4df30c..57e41fa 100644 --- a/nearby/presence/np_adv/tests/examples_v1.rs +++ b/nearby/presence/np_adv/tests/examples_v1.rs
@@ -14,36 +14,45 @@ #![allow(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::panic)] -use crypto_provider::{CryptoProvider, CryptoRng}; +use crypto_provider::{ed25519, CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; -use np_adv::extended::data_elements::TxPowerDataElement; -use np_adv::extended::serialize::{AdvertisementType, PublicSectionEncoder, SingleTypeDataElement}; -use np_adv::extended::NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT; -use np_adv::shared_data::TxPower; +use np_adv::credential::matched::{ + EmptyMatchedCredential, MetadataMatchedCredential, WithMatchedCredential, +}; +use np_adv::extended::deserialize::{Section, V1DeserializedSection}; +use np_adv::extended::{V1IdentityToken, V1_ENCODING_UNENCRYPTED}; use np_adv::{ credential::{ book::CredentialBookBuilder, - v1::{SimpleSignedBroadcastCryptoMaterial, V1DiscoveryCredential, V1}, - EmptyMatchedCredential, MatchableCredential, MetadataMatchedCredential, + v1::{V1BroadcastCredential, V1DiscoveryCredential, V1}, + MatchableCredential, }, - de_type::*, + deserialization_arena, deserialize_advertisement, extended::{ - deserialize::{Section, VerificationMode}, - serialize::{AdvBuilder, SignedEncryptedSectionEncoder}, + data_elements::TxPowerDataElement, + deserialize::VerificationMode, + serialize::{ + AdvBuilder, AdvertisementType, SignedEncryptedSectionEncoder, SingleTypeDataElement, + UnencryptedSectionEncoder, + }, + NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, }, - PlaintextIdentityMode, *, + shared_data::TxPower, + AdvDeserializationError, AdvDeserializationErrorDetailsHazmat, }; -use np_hkdf::v1_salt; +use np_hkdf::{v1_salt, DerivedSectionKeys}; use serde::{Deserialize, Serialize}; +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; + #[test] fn v1_deser_plaintext() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); - let mut section_builder = adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(6).unwrap())) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let adv = adv_builder.into_advertisement(); let cred_book = CredentialBookBuilder::<EmptyMatchedCredential>::build_cached_slice_book::< @@ -69,12 +78,11 @@ V1DeserializedSection::Plaintext(s) => s, _ => panic!("this is a plaintext adv"), }; - assert_eq!(PlaintextIdentityMode::Public, section.identity()); let data_elements = section.iter_data_elements().collect::<Result<Vec<_>, _>>().unwrap(); assert_eq!(1, data_elements.len()); let de = &data_elements[0]; - assert_eq!(v1_salt::DataElementOffset::from(1), de.offset()); + assert_eq!(v1_salt::DataElementOffset::from(0), de.offset()); assert_eq!(TxPowerDataElement::DE_TYPE, de.de_type()); assert_eq!(&[6], de.contents()); } @@ -104,14 +112,13 @@ fn v1_deser_ciphertext() { // identity material let mut rng = <CryptoProviderImpl as CryptoProvider>::CryptoRng::new(); - let metadata_key: [u8; 16] = rng.gen(); - let metadata_key = MetadataKey(metadata_key); - let key_pair = np_ed25519::KeyPair::<CryptoProviderImpl>::generate(); + let token_array: [u8; 16] = rng.gen(); + let identity_token = V1IdentityToken::from(token_array); + let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(); let key_seed = rng.gen(); let hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); - let broadcast_cm = - SimpleSignedBroadcastCryptoMaterial::new(key_seed, metadata_key, key_pair.private_key()); + let broadcast_cred = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone()); // Serialize and encrypt some identity metadata (sender-side) let sender_metadata = IdentityMetadata { @@ -121,37 +128,40 @@ }; let sender_metadata_bytes = sender_metadata.to_bytes(); let encrypted_sender_metadata = MetadataMatchedCredential::<Vec<u8>>::encrypt_from_plaintext::< - _, - _, + V1, CryptoProviderImpl, - >(&broadcast_cm, &sender_metadata_bytes); + >(&hkdf, identity_token, &sender_metadata_bytes); // prepare advertisement let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted); let mut section_builder = adv_builder - .section_builder(SignedEncryptedSectionEncoder::<CryptoProviderImpl>::new_random_salt( + .section_builder(SignedEncryptedSectionEncoder::new_random_salt::<CryptoProviderImpl>( &mut rng, - EncryptedIdentityDataElementType::Private, - &broadcast_cm, + &broadcast_cred, )) .unwrap(); section_builder .add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(7).unwrap())) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); let adv = adv_builder.into_advertisement(); - let discovery_credential = V1DiscoveryCredential::new::<CryptoProviderImpl>( + let discovery_credential = V1DiscoveryCredential::new( key_seed, + [0; 32], [0; 32], // Zeroing out MIC HMAC, since it's unused in examples here. - hkdf.extended_signed_metadata_key_hmac_key().calculate_hmac(&metadata_key.0), - key_pair.public().to_bytes(), - ) - .expect("Public key bytes are valid points on the curve since theyc ame from the keypair"); + hkdf.v1_signature_keys() + .identity_token_hmac_key() + .calculate_hmac::<CryptoProviderImpl>(identity_token.bytes()), + private_key.derive_public_key::<Ed25519ProviderImpl>(), + ); let credentials: [MatchableCredential<V1, MetadataMatchedCredential<_>>; 1] = - [MatchableCredential { discovery_credential, match_data: encrypted_sender_metadata }]; + [MatchableCredential { + discovery_credential, + match_data: encrypted_sender_metadata.clone(), + }]; let cred_book = CredentialBookBuilder::build_cached_slice_book::<0, 0, CryptoProviderImpl>( &[], &credentials, @@ -182,21 +192,52 @@ let section = matched.contents(); - assert_eq!(EncryptedIdentityDataElementType::Private, section.identity_type()); assert_eq!(VerificationMode::Signature, section.verification_mode()); - assert_eq!(metadata_key, section.metadata_key()); + assert_eq!(&identity_token, section.identity_token()); let data_elements = section.iter_data_elements().collect::<Result<Vec<_>, _>>().unwrap(); assert_eq!(1, data_elements.len()); let de = &data_elements[0]; - assert_eq!(v1_salt::DataElementOffset::from(2), de.offset()); + assert_eq!(v1_salt::DataElementOffset::from(0), de.offset()); assert_eq!(TxPowerDataElement::DE_TYPE, de.de_type()); assert_eq!(&[7], de.contents()); + + // Uncomment if you need to regenerate C++ v1_private_identity_tests data + // { + // use test_helper::hex_bytes; + // use np_adv::extended::salt::MultiSalt; + // use np_adv_credential_matched::MatchedCredential; + // println!("adv:\n{}", hex_bytes(adv.as_slice())); + // println!("key seed:\n{}", hex_bytes(key_seed)); + // println!( + // "identity token hmac:\n{}", + // hex_bytes( + // hkdf.v1_signature_keys() + // .identity_token_hmac_key() + // .calculate_hmac(identity_token.bytes()) + // ) + // ); + // println!("public key:\n{}", hex_bytes(key_pair.public().to_bytes())); + // println!( + // "encrypted metadata:\n{}", + // hex_bytes(encrypted_sender_metadata.fetch_encrypted_metadata().unwrap()) + // ); + // std::println!("offset is: {:?}", de.offset()); + // let derived_salt = match section.salt() { + // MultiSalt::Short(_) => panic!(), + // MultiSalt::Extended(s) => { + // s.derive::<16, CryptoProviderImpl>(Some(de.offset())).unwrap() + // } + // }; + // println!("DE derived salt:\n{}", hex_bytes(derived_salt)); + // panic!(); + // } } #[test] fn v1_deser_no_section() { + // TODO: we shouldn't allow this invalid advertisement to be serialized let adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); let adv = adv_builder.into_advertisement(); let cred_book = CredentialBookBuilder::<EmptyMatchedCredential>::build_cached_slice_book::< @@ -220,19 +261,18 @@ fn v1_deser_plaintext_over_max_sections() { let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext); for _ in 0..NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT { - let mut section_builder = - adv_builder.section_builder(PublicSectionEncoder::default()).unwrap(); + let mut section_builder = adv_builder.section_builder(UnencryptedSectionEncoder).unwrap(); section_builder .add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(7).unwrap())) .unwrap(); - section_builder.add_to_advertisement(); + section_builder.add_to_advertisement::<CryptoProviderImpl>(); } let mut adv = adv_builder.into_advertisement().as_slice().to_vec(); // Push an extra section adv.extend_from_slice( [ 0x01, // Section header - 0x03, // Public identity + V1_ENCODING_UNENCRYPTED, ] .as_slice(), );
diff --git a/nearby/presence/np_adv_dynamic/Cargo.toml b/nearby/presence/np_adv_dynamic/Cargo.toml index 2e36ec5..5eb6863 100644 --- a/nearby/presence/np_adv_dynamic/Cargo.toml +++ b/nearby/presence/np_adv_dynamic/Cargo.toml
@@ -12,3 +12,4 @@ np_adv = { workspace = true, features = ["alloc"] } crypto_provider.workspace = true sink.workspace = true +np_hkdf.workspace = true
diff --git a/nearby/presence/np_adv_dynamic/src/extended.rs b/nearby/presence/np_adv_dynamic/src/extended.rs index 07de504..c25be74 100644 --- a/nearby/presence/np_adv_dynamic/src/extended.rs +++ b/nearby/presence/np_adv_dynamic/src/extended.rs
@@ -13,6 +13,7 @@ // limitations under the License. use crypto_provider::CryptoProvider; +use np_adv::extended::salt::MultiSalt; use np_adv::{extended::data_elements::*, extended::serialize::*, shared_data::*}; use sink::Sink; use std::fmt::{Display, Formatter}; @@ -62,22 +63,18 @@ } } -fn wrap_owning_section_builder<C: CryptoProvider, S: Into<BoxedSectionBuilder<AdvBuilder, C>>>( +fn wrap_owning_section_builder<S: Into<BoxedSectionBuilder<AdvBuilder>>>( maybe_section_builder: Result<S, (AdvBuilder, AddSectionError)>, -) -> Result<BoxedSectionBuilder<AdvBuilder, C>, (BoxedAdvBuilder, BoxedAddSectionError)> { +) -> Result<BoxedSectionBuilder<AdvBuilder>, (BoxedAdvBuilder, BoxedAddSectionError)> { match maybe_section_builder { Ok(section_builder) => Ok(section_builder.into()), Err((adv_builder, err)) => Err((adv_builder.into(), err.into())), } } -fn wrap_mut_ref_section_builder< - 'a, - C: CryptoProvider, - S: Into<BoxedSectionBuilder<&'a mut AdvBuilder, C>>, ->( +fn wrap_mut_ref_section_builder<'a, S: Into<BoxedSectionBuilder<&'a mut AdvBuilder>>>( maybe_section_builder: Result<S, AddSectionError>, -) -> Result<BoxedSectionBuilder<&'a mut AdvBuilder, C>, BoxedAddSectionError> { +) -> Result<BoxedSectionBuilder<&'a mut AdvBuilder>, BoxedAddSectionError> { let section_builder = maybe_section_builder?; Ok(section_builder.into()) } @@ -98,42 +95,42 @@ /// builder, if the operation was successful. Otherwise, /// this advertisement builder will be returned back to the /// caller unaltered as part of the `Err` arm. - pub fn into_section_builder<C: CryptoProvider>( + pub fn into_section_builder( self, - identity: BoxedIdentity<C>, - ) -> Result<BoxedSectionBuilder<AdvBuilder, C>, (Self, BoxedAddSectionError)> { + identity: BoxedEncoder, + ) -> Result<BoxedSectionBuilder<AdvBuilder>, (Self, BoxedAddSectionError)> { match identity { - BoxedIdentity::PublicIdentity => wrap_owning_section_builder( - self.adv_builder.into_section_builder(PublicSectionEncoder::default()), + BoxedEncoder::Unencrypted => wrap_owning_section_builder( + self.adv_builder.into_section_builder(UnencryptedSectionEncoder), ), - BoxedIdentity::MicEncrypted(ident) => { + BoxedEncoder::MicEncrypted(ident) => { wrap_owning_section_builder(self.adv_builder.into_section_builder(ident)) } - BoxedIdentity::SignedEncrypted(ident) => { + BoxedEncoder::SignedEncrypted(ident) => { wrap_owning_section_builder(self.adv_builder.into_section_builder(ident)) } } } - /// Create a section builder using the given identity. + /// Create a section builder using the given encoder. /// /// Returns `Err` if the underlying advertisement builder /// yields an error when attempting to add a new section /// (typically because there's no more available adv space), /// or if the requested identity requires salt, and the /// advertisement builder is salt-less. - pub fn section_builder<C: CryptoProvider>( + pub fn section_builder( &mut self, - identity: BoxedIdentity<C>, - ) -> Result<BoxedSectionBuilder<&mut AdvBuilder, C>, BoxedAddSectionError> { - match identity { - BoxedIdentity::PublicIdentity => wrap_mut_ref_section_builder( - self.adv_builder.section_builder(PublicSectionEncoder::default()), + encoder: BoxedEncoder, + ) -> Result<BoxedSectionBuilder<&mut AdvBuilder>, BoxedAddSectionError> { + match encoder { + BoxedEncoder::Unencrypted => wrap_mut_ref_section_builder( + self.adv_builder.section_builder(UnencryptedSectionEncoder), ), - BoxedIdentity::MicEncrypted(ident) => { + BoxedEncoder::MicEncrypted(ident) => { wrap_mut_ref_section_builder(self.adv_builder.section_builder(ident)) } - BoxedIdentity::SignedEncrypted(ident) => { + BoxedEncoder::SignedEncrypted(ident) => { wrap_mut_ref_section_builder(self.adv_builder.section_builder(ident)) } } @@ -145,29 +142,29 @@ } } -/// A wrapped v1 identity whose type is given at run-time. -pub enum BoxedIdentity<C: CryptoProvider> { - /// Public identity. - PublicIdentity, - /// An encrypted identity leveraging MIC for verification. - MicEncrypted(MicEncryptedSectionEncoder<C>), - /// An encrypted identity leveraging signatures for verification. - SignedEncrypted(SignedEncryptedSectionEncoder<C>), +/// A wrapped v1 encoder whose type is given at run-time. +pub enum BoxedEncoder { + /// Unencrypted encoder. + Unencrypted, + /// An encrypted encoder leveraging MIC for verification. + MicEncrypted(MicEncryptedSectionEncoder<MultiSalt>), + /// An encrypted encoder leveraging signatures for verification. + SignedEncrypted(SignedEncryptedSectionEncoder), } /// A `SectionBuilder` whose corresponding Identity /// and salted-ness is given at run-time instead of /// at compile-time. -pub enum BoxedSectionBuilder<R: AsMut<AdvBuilder>, C: CryptoProvider> { +pub enum BoxedSectionBuilder<R: AsMut<AdvBuilder>> { /// A builder for a public section. - Public(Box<SectionBuilder<R, PublicSectionEncoder>>), + Public(Box<SectionBuilder<R, UnencryptedSectionEncoder>>), /// A builder for a MIC-verified section. - MicEncrypted(Box<SectionBuilder<R, MicEncryptedSectionEncoder<C>>>), + MicEncrypted(Box<SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>>), /// A builder for a signature-verified section. - SignedEncrypted(Box<SectionBuilder<R, SignedEncryptedSectionEncoder<C>>>), + SignedEncrypted(Box<SectionBuilder<R, SignedEncryptedSectionEncoder>>), } -impl<C: CryptoProvider> BoxedSectionBuilder<AdvBuilder, C> { +impl BoxedSectionBuilder<AdvBuilder> { /// Gets the 0-based index of the section currently under construction /// in the context of the containing advertisement. pub fn section_index(&self) -> usize { @@ -179,28 +176,28 @@ } /// Add this builder to the advertisement that created it, /// returning the containing advertisement builder. - pub fn add_to_advertisement(self) -> BoxedAdvBuilder { + pub fn add_to_advertisement<C: CryptoProvider>(self) -> BoxedAdvBuilder { let adv_builder = match self { - BoxedSectionBuilder::Public(x) => x.add_to_advertisement(), - BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement(), - BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement(), + BoxedSectionBuilder::Public(x) => x.add_to_advertisement::<C>(), + BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement::<C>(), + BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement::<C>(), }; BoxedAdvBuilder::from(adv_builder) } } -impl<'a, C: CryptoProvider> BoxedSectionBuilder<&'a mut AdvBuilder, C> { +impl<'a> BoxedSectionBuilder<&'a mut AdvBuilder> { /// Add this builder to the advertisement that created it. - pub fn add_to_advertisement(self) { + pub fn add_to_advertisement<C: CryptoProvider>(self) { match self { - BoxedSectionBuilder::Public(x) => x.add_to_advertisement(), - BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement(), - BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement(), + BoxedSectionBuilder::Public(x) => x.add_to_advertisement::<C>(), + BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement::<C>(), + BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement::<C>(), } } } -impl<R: AsMut<AdvBuilder>, C: CryptoProvider> BoxedSectionBuilder<R, C> { +impl<R: AsMut<AdvBuilder>> BoxedSectionBuilder<R> { /// Returns true if this wraps a section builder which /// leverages some encrypted identity. pub fn is_encrypted(&self) -> bool { @@ -211,15 +208,16 @@ } } /// Gets the derived salt of the next DE to be added to the section, - /// if this section-builder corresponds to an encrypted section. + /// if this section-builder corresponds to an encrypted section that can + /// provide per-DE salts. /// Otherwise, returns nothing. /// /// Suitable for scenarios (like FFI) where a closure would be inappropriate /// for DE construction, and interaction with the client is preferred. - pub fn next_de_salt(&self) -> Option<DeSalt<C>> { + pub fn next_de_salt(&self) -> Option<DeSalt> { match self { BoxedSectionBuilder::Public(_) => None, - BoxedSectionBuilder::MicEncrypted(x) => Some(x.next_de_salt()), + BoxedSectionBuilder::MicEncrypted(x) => x.next_de_salt(), BoxedSectionBuilder::SignedEncrypted(x) => Some(x.next_de_salt()), } } @@ -230,19 +228,16 @@ /// if any salt has been specified for the surrounding advertisement. pub fn add_de_res<E>( &mut self, - build_de: impl FnOnce(Option<DeSalt<C>>) -> Result<BoxedWriteDataElement, E>, + build_de: impl FnOnce(Option<DeSalt>) -> Result<BoxedWriteDataElement, E>, ) -> Result<(), AddDataElementError<E>> { match self { BoxedSectionBuilder::Public(x) => { let build_de_modified = |()| build_de(None); x.add_de_res(build_de_modified) } - BoxedSectionBuilder::MicEncrypted(x) => { - let build_de_modified = |de_salt: DeSalt<C>| build_de(Some(de_salt)); - x.add_de_res(build_de_modified) - } + BoxedSectionBuilder::MicEncrypted(x) => x.add_de_res(build_de), BoxedSectionBuilder::SignedEncrypted(x) => { - let build_de_modified = |de_salt: DeSalt<C>| build_de(Some(de_salt)); + let build_de_modified = |de_salt: DeSalt| build_de(Some(de_salt)); x.add_de_res(build_de_modified) } } @@ -250,32 +245,32 @@ /// Like add_de_res, but for infalliable closures pub fn add_de( &mut self, - build_de: impl FnOnce(Option<DeSalt<C>>) -> BoxedWriteDataElement, + build_de: impl FnOnce(Option<DeSalt>) -> BoxedWriteDataElement, ) -> Result<(), AddDataElementError<()>> { self.add_de_res(|derived_salt| Ok::<_, ()>(build_de(derived_salt))) } } -impl<R: AsMut<AdvBuilder>, C: CryptoProvider> From<SectionBuilder<R, PublicSectionEncoder>> - for BoxedSectionBuilder<R, C> +impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, UnencryptedSectionEncoder>> + for BoxedSectionBuilder<R> { - fn from(section_builder: SectionBuilder<R, PublicSectionEncoder>) -> Self { + fn from(section_builder: SectionBuilder<R, UnencryptedSectionEncoder>) -> Self { BoxedSectionBuilder::Public(Box::new(section_builder)) } } -impl<R: AsMut<AdvBuilder>, C: CryptoProvider> From<SectionBuilder<R, MicEncryptedSectionEncoder<C>>> - for BoxedSectionBuilder<R, C> +impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>> + for BoxedSectionBuilder<R> { - fn from(section_builder: SectionBuilder<R, MicEncryptedSectionEncoder<C>>) -> Self { + fn from(section_builder: SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>) -> Self { BoxedSectionBuilder::MicEncrypted(Box::new(section_builder)) } } -impl<R: AsMut<AdvBuilder>, C: CryptoProvider> - From<SectionBuilder<R, SignedEncryptedSectionEncoder<C>>> for BoxedSectionBuilder<R, C> +impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, SignedEncryptedSectionEncoder>> + for BoxedSectionBuilder<R> { - fn from(section_builder: SectionBuilder<R, SignedEncryptedSectionEncoder<C>>) -> Self { + fn from(section_builder: SectionBuilder<R, SignedEncryptedSectionEncoder>) -> Self { BoxedSectionBuilder::SignedEncrypted(Box::new(section_builder)) } }
diff --git a/nearby/presence/np_adv_dynamic/src/legacy.rs b/nearby/presence/np_adv_dynamic/src/legacy.rs index 83ce6ab..68eb1bc 100644 --- a/nearby/presence/np_adv_dynamic/src/legacy.rs +++ b/nearby/presence/np_adv_dynamic/src/legacy.rs
@@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use array_view::ArrayView; use crypto_provider::CryptoProvider; -use np_adv::legacy::actions::*; -use np_adv::legacy::data_elements::*; -use np_adv::legacy::serialize::*; -use np_adv::legacy::*; -use np_adv::shared_data::*; -use np_adv::PublicIdentity; +use np_adv::{ + legacy::{ + data_elements::{actions::*, tx_power::TxPowerDataElement, *}, + serialize::*, + *, + }, + shared_data::*, +}; use std::fmt::{Display, Formatter}; /// Wrapper around a V0 advertisement builder which @@ -29,10 +30,10 @@ /// Generic over the Aes algorithm used for any encrypted identities, /// since that is generally specified at compile-time. pub enum BoxedAdvBuilder<C: CryptoProvider> { - /// Builder for public advertisements. - Public(AdvBuilder<PublicIdentity>), - /// Builder for LDT-encryptedadvertisements. - Ldt(AdvBuilder<LdtIdentity<C>>), + /// Builder for unencrypted advertisements. + Unencrypted(AdvBuilder<UnencryptedEncoder>), + /// Builder for LDT-encrypted advertisements. + Ldt(AdvBuilder<LdtEncoder<C>>), } /// Wrapper around possible errors which occur only during @@ -41,7 +42,9 @@ pub enum BoxedAdvConstructionError { /// An error originating from a problem with LDT /// encryption of the advertisement contents. - Ldt(LdtPostprocessError), + Ldt(LdtEncodeError), + /// An error from encoding an unencrypted adv + Unencrypted(UnencryptedEncodeError), } impl<C: CryptoProvider> BoxedAdvBuilder<C> { @@ -49,15 +52,17 @@ /// leverages some encrypted identity. pub fn is_encrypted(&self) -> bool { match self { - BoxedAdvBuilder::Public(_) => false, + BoxedAdvBuilder::Unencrypted(_) => false, BoxedAdvBuilder::Ldt(_) => true, } } /// Constructs a new BoxedAdvBuilder from the given BoxedIdentity - pub fn new(identity: BoxedIdentity<C>) -> Self { + pub fn new(identity: BoxedEncoder<C>) -> Self { match identity { - BoxedIdentity::Public(identity) => BoxedAdvBuilder::Public(AdvBuilder::new(identity)), - BoxedIdentity::LdtIdentity(identity) => BoxedAdvBuilder::Ldt(AdvBuilder::new(identity)), + BoxedEncoder::Unencrypted(encoder) => { + BoxedAdvBuilder::Unencrypted(AdvBuilder::new(encoder)) + } + BoxedEncoder::LdtEncrypted(encoder) => BoxedAdvBuilder::Ldt(AdvBuilder::new(encoder)), } } /// Attempts to add a data element to the advertisement @@ -66,10 +71,10 @@ /// if something went wrong in the attempt to add the DE. pub fn add_data_element( &mut self, - data_element: ToBoxedDataElementBundle, + data_element: ToBoxedSerializeDataElement, ) -> Result<(), BoxedAddDataElementError> { match self { - BoxedAdvBuilder::Public(public_builder) => { + BoxedAdvBuilder::Unencrypted(public_builder) => { //Verify that we can get the data element as plaintext let maybe_plaintext_data_element = data_element.to_plaintext(); match maybe_plaintext_data_element { @@ -93,15 +98,10 @@ } /// Consume this BoxedAdvBuilder and attempt to create /// a serialized advertisement including the added DEs. - pub fn into_advertisement( - self, - ) -> Result<ArrayView<u8, BLE_ADV_SVC_CONTENT_LEN>, BoxedAdvConstructionError> { + pub fn into_advertisement(self) -> Result<SerializedAdv, BoxedAdvConstructionError> { match self { - BoxedAdvBuilder::Public(x) => { - match x.into_advertisement() { - Ok(x) => Ok(x), - Err(x) => match x {}, //Infallible - } + BoxedAdvBuilder::Unencrypted(x) => { + x.into_advertisement().map_err(BoxedAdvConstructionError::Unencrypted) } BoxedAdvBuilder::Ldt(x) => { x.into_advertisement().map_err(BoxedAdvConstructionError::Ldt) @@ -145,121 +145,100 @@ } } -/// Trait object reference to a `ToDataElementBundle<I>` with lifetime `'a`. -/// Implements `ToDataElementBundle<I>` by deferring to the wrapped trait object. -pub struct DynamicToDataElementBundle<'a, I: PacketFlavor> { - wrapped: &'a dyn ToDataElementBundle<I>, -} - -impl<'a, I: PacketFlavor> From<&'a dyn ToDataElementBundle<I>> - for DynamicToDataElementBundle<'a, I> -{ - fn from(wrapped: &'a dyn ToDataElementBundle<I>) -> Self { - DynamicToDataElementBundle { wrapped } - } -} - -impl<'a, I: PacketFlavor> ToDataElementBundle<I> for DynamicToDataElementBundle<'a, I> { - fn to_de_bundle(&self) -> DataElementBundle<I> { - self.wrapped.to_de_bundle() - } -} - /// Trait for types which can provide trait object -/// references to either plaintext or ciphertext [ToDataElementBundle] -pub trait ToMultiFlavorElementBundle { - /// Gets the associated trait object reference to a `ToDataElementBundle<Plaintext>` +/// references to either plaintext or ciphertext [SerializeDataElement] +pub trait ToMultiFlavorSerializeDataElement { + /// Gets the associated trait object reference to a `SerializeDataElement<Plaintext>` /// with the same lifetime as a reference to the implementor. - fn to_plaintext(&self) -> DynamicToDataElementBundle<Plaintext>; + fn to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext>; - /// Gets the associated trait object reference to a `ToDataElementBundle<Ciphertext>` + /// Gets the associated trait object reference to a `SerializeDataElement<Ciphertext>` /// with the same lifetime as a reference to the implementor. - fn to_ciphertext(&self) -> DynamicToDataElementBundle<Ciphertext>; + fn to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext>; } -/// Blanket impl of [ToMultiFlavorElementBundle] for implementors of [ToDataElementBundle] +/// Blanket impl of [ToMultiFlavorSerializeDataElement] for implementors of [SerializeDataElement] /// for both [Plaintext] and [Ciphertext] packet flavors. -impl<T: ToDataElementBundle<Plaintext> + ToDataElementBundle<Ciphertext>> ToMultiFlavorElementBundle - for T +impl<T: SerializeDataElement<Plaintext> + SerializeDataElement<Ciphertext>> + ToMultiFlavorSerializeDataElement for T { - fn to_plaintext(&self) -> DynamicToDataElementBundle<Plaintext> { - let reference: &dyn ToDataElementBundle<Plaintext> = self; + fn to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext> { + let reference: &dyn SerializeDataElement<Plaintext> = self; reference.into() } - fn to_ciphertext(&self) -> DynamicToDataElementBundle<Ciphertext> { - let reference: &dyn ToDataElementBundle<Ciphertext> = self; + fn to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext> { + let reference: &dyn SerializeDataElement<Ciphertext> = self; reference.into() } } -/// Boxed trait object version of [ToDataElementBundle] which incorporates +/// Boxed trait object version of [SerializeDataElement] which incorporates /// all possible variants on generatable packet flavoring -/// (`Plaintext`, `Ciphertext`, or both, as a [ToMultiFlavorElementBundle]) -pub enum ToBoxedDataElementBundle { +/// (`Plaintext`, `Ciphertext`, or both, as a [ToMultiFlavorSerializeDataElement]) +pub enum ToBoxedSerializeDataElement { /// The underlying DE is plaintext-only. - Plaintext(Box<dyn ToDataElementBundle<Plaintext>>), + Plaintext(Box<dyn SerializeDataElement<Plaintext>>), /// The underlying DE is ciphertext-only. - Ciphertext(Box<dyn ToDataElementBundle<Ciphertext>>), + Ciphertext(Box<dyn SerializeDataElement<Ciphertext>>), /// The underlying DE may exist in plaintext or /// in ciphertext advertisements. - Both(Box<dyn ToMultiFlavorElementBundle>), + Both(Box<dyn ToMultiFlavorSerializeDataElement>), } -impl ToBoxedDataElementBundle { - /// If this [ToBoxedDataElementBundle] can generate plaintext, returns - /// a trait object reference to a `ToDataElementBundle<Plaintext>` - pub fn to_plaintext(&self) -> Option<DynamicToDataElementBundle<Plaintext>> { +impl ToBoxedSerializeDataElement { + /// If this [ToBoxedSerializeDataElement] can generate plaintext, returns + /// a trait object reference to a `SerializeDataElement<Plaintext>` + pub fn to_plaintext(&self) -> Option<DynamicSerializeDataElement<Plaintext>> { match &self { - ToBoxedDataElementBundle::Plaintext(x) => Some(x.as_ref().into()), - ToBoxedDataElementBundle::Ciphertext(_) => None, - ToBoxedDataElementBundle::Both(x) => Some(x.as_ref().to_plaintext()), + ToBoxedSerializeDataElement::Plaintext(x) => Some(x.as_ref().into()), + ToBoxedSerializeDataElement::Ciphertext(_) => None, + ToBoxedSerializeDataElement::Both(x) => Some(x.as_ref().to_plaintext()), } } - /// If this [ToBoxedDataElementBundle] can generate ciphertext, returns - /// a trait object reference to a `ToDataElementBundle<Ciphertext>` - pub fn to_ciphertext(&self) -> Option<DynamicToDataElementBundle<Ciphertext>> { + /// If this [ToBoxedSerializeDataElement] can generate ciphertext, returns + /// a trait object reference to a `SerializeDataElement<Ciphertext>` + pub fn to_ciphertext(&self) -> Option<DynamicSerializeDataElement<Ciphertext>> { match &self { - ToBoxedDataElementBundle::Plaintext(_) => None, - ToBoxedDataElementBundle::Ciphertext(x) => Some(x.as_ref().into()), - ToBoxedDataElementBundle::Both(x) => Some(x.as_ref().to_ciphertext()), + ToBoxedSerializeDataElement::Plaintext(_) => None, + ToBoxedSerializeDataElement::Ciphertext(x) => Some(x.as_ref().into()), + ToBoxedSerializeDataElement::Both(x) => Some(x.as_ref().to_ciphertext()), } } } -/// Boxed version of implementors of the Identity trait. -/// A is the underlying Aes algorithm leveraged by ciphertext-based identities. -pub enum BoxedIdentity<C: CryptoProvider> { - /// Public Identity. - Public(PublicIdentity), - /// An encrypted identity, using LDT encryption. - LdtIdentity(LdtIdentity<C>), +/// Boxed version of implementors of the [AdvEncoder] trait. +pub enum BoxedEncoder<C: CryptoProvider> { + /// Unencrypted encoding. + Unencrypted(UnencryptedEncoder), + /// An encrypted encoding, using LDT encryption. + LdtEncrypted(LdtEncoder<C>), } -impl<C: CryptoProvider> From<PublicIdentity> for BoxedIdentity<C> { - fn from(public_identity: PublicIdentity) -> BoxedIdentity<C> { - BoxedIdentity::Public(public_identity) +impl<C: CryptoProvider> From<UnencryptedEncoder> for BoxedEncoder<C> { + fn from(encoder: UnencryptedEncoder) -> BoxedEncoder<C> { + BoxedEncoder::Unencrypted(encoder) } } -impl<C: CryptoProvider> From<LdtIdentity<C>> for BoxedIdentity<C> { - fn from(ldt_identity: LdtIdentity<C>) -> BoxedIdentity<C> { - BoxedIdentity::LdtIdentity(ldt_identity) +impl<C: CryptoProvider> From<LdtEncoder<C>> for BoxedEncoder<C> { + fn from(encoder: LdtEncoder<C>) -> BoxedEncoder<C> { + BoxedEncoder::LdtEncrypted(encoder) } } -impl From<TxPower> for ToBoxedDataElementBundle { +impl From<TxPower> for ToBoxedSerializeDataElement { fn from(data: TxPower) -> Self { - ToBoxedDataElementBundle::Both(Box::new(TxPowerDataElement::from(data))) + ToBoxedSerializeDataElement::Both(Box::new(TxPowerDataElement::from(data))) } } -impl From<BoxedActionBits> for ToBoxedDataElementBundle { +impl From<BoxedActionBits> for ToBoxedSerializeDataElement { fn from(action_bits: BoxedActionBits) -> Self { match action_bits { - BoxedActionBits::Plaintext(action_bits) => { - ToBoxedDataElementBundle::Plaintext(Box::new(ActionsDataElement::from(action_bits))) - } - BoxedActionBits::Ciphertext(action_bits) => ToBoxedDataElementBundle::Ciphertext( + BoxedActionBits::Plaintext(action_bits) => ToBoxedSerializeDataElement::Plaintext( + Box::new(ActionsDataElement::from(action_bits)), + ), + BoxedActionBits::Ciphertext(action_bits) => ToBoxedSerializeDataElement::Ciphertext( Box::new(ActionsDataElement::from(action_bits)), ), } @@ -269,8 +248,10 @@ /// Boxed version of `ToActionElement` which allows abstracting over /// what packet flavors are supported by a given action. pub enum ToBoxedActionElement { - /// A context-sync sequence number. - ContextSyncSeqNum(ContextSyncSeqNum), + /// Action bit for cross device SDK. + CrossDevSdk(bool), + /// Action bit for call transfer. + CallTransfer(bool), /// Action bit for active unlock. ActiveUnlock(bool), /// Action bit for nearby share. @@ -279,12 +260,6 @@ InstantTethering(bool), /// Action bit for PhoneHub. PhoneHub(bool), - /// Action bit for Finder. - Finder(bool), - /// Action bit for Fast Pair/SASS - FastPairSass(bool), - /// Action bit for Presence Manager. - PresenceManager(bool), } /// [`ActionBits`] with runtime-determined packet flavoring @@ -323,25 +298,17 @@ } } - /// Gets the context-sync sequence number from these boxed action bits. - pub fn get_context_sync_seq_num(&self) -> ContextSyncSeqNum { - match self { - BoxedActionBits::Plaintext(x) => x.context_sync_seq_num(), - BoxedActionBits::Ciphertext(x) => x.context_sync_seq_num(), - } - } - /// Returns whether a boolean action type is set in these action bits, or `None` /// if the given action type does not represent a boolean (e.g: a context-sync /// sequence number). - pub fn has_action(&self, action_type: &ActionType) -> Option<bool> { + pub fn has_action(&self, action_type: ActionType) -> bool { match self { BoxedActionBits::Plaintext(x) => x.has_action(action_type), BoxedActionBits::Ciphertext(x) => x.has_action(action_type), } } - fn set<F: PacketFlavor, E: ToActionElement<F>>( + fn set<F: PacketFlavor, E: ActionElementFlavor<F>>( action_bits: &mut ActionBits<F>, to_element: E, ) -> Result<(), BoxedSetActionFlavorError> { @@ -358,18 +325,24 @@ ) -> Result<(), BoxedSetActionFlavorError> { match self { BoxedActionBits::Plaintext(action_bits) => match to_element { - ToBoxedActionElement::ContextSyncSeqNum(x) => Self::set(action_bits, x), + ToBoxedActionElement::CrossDevSdk(b) => { + Self::set(action_bits, CrossDevSdk::from(b)) + } ToBoxedActionElement::NearbyShare(b) => { Self::set(action_bits, NearbyShare::from(b)) } - ToBoxedActionElement::Finder(b) => Self::set(action_bits, Finder::from(b)), - ToBoxedActionElement::FastPairSass(b) => { - Self::set(action_bits, FastPairSass::from(b)) - } - _ => Err(BoxedSetActionFlavorError), + ToBoxedActionElement::CallTransfer(_) + | ToBoxedActionElement::ActiveUnlock(_) + | ToBoxedActionElement::InstantTethering(_) + | ToBoxedActionElement::PhoneHub(_) => Err(BoxedSetActionFlavorError), }, BoxedActionBits::Ciphertext(action_bits) => match to_element { - ToBoxedActionElement::ContextSyncSeqNum(x) => Self::set(action_bits, x), + ToBoxedActionElement::CrossDevSdk(b) => { + Self::set(action_bits, CrossDevSdk::from(b)) + } + ToBoxedActionElement::CallTransfer(b) => { + Self::set(action_bits, CallTransfer::from(b)) + } ToBoxedActionElement::ActiveUnlock(b) => { Self::set(action_bits, ActiveUnlock::from(b)) } @@ -380,10 +353,6 @@ Self::set(action_bits, InstantTethering::from(b)) } ToBoxedActionElement::PhoneHub(b) => Self::set(action_bits, PhoneHub::from(b)), - ToBoxedActionElement::PresenceManager(b) => { - Self::set(action_bits, PresenceManager::from(b)) - } - _ => Err(BoxedSetActionFlavorError), }, } }
diff --git a/nearby/presence/np_c_ffi/include/c/np_c_ffi.h b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h index 0ff152f..0eb9ecd 100644 --- a/nearby/presence/np_c_ffi/include/c/np_c_ffi.h +++ b/nearby/presence/np_c_ffi/include/c/np_c_ffi.h
@@ -35,6 +35,19 @@ #include <stdlib.h> /** + * The possible boolean action types which can be present in an Actions data element + */ +enum np_ffi_ActionType { + NP_FFI_ACTION_TYPE_CROSS_DEV_SDK = 1, + NP_FFI_ACTION_TYPE_CALL_TRANSFER = 4, + NP_FFI_ACTION_TYPE_ACTIVE_UNLOCK = 8, + NP_FFI_ACTION_TYPE_NEARBY_SHARE = 9, + NP_FFI_ACTION_TYPE_INSTANT_TETHERING = 10, + NP_FFI_ACTION_TYPE_PHONE_HUB = 11, +}; +typedef uint8_t np_ffi_ActionType; + +/** * Result type for trying to add a V0 credential to a credential-slab. */ enum np_ffi_AddV0CredentialToSlabResult { @@ -161,37 +174,6 @@ typedef uint8_t np_ffi_AdvertisementBuilderKind; /** - * The possible boolean action types which can be present in an Actions data element - */ -enum np_ffi_BooleanActionType { - NP_FFI_BOOLEAN_ACTION_TYPE_ACTIVE_UNLOCK = 8, - NP_FFI_BOOLEAN_ACTION_TYPE_NEARBY_SHARE = 9, - NP_FFI_BOOLEAN_ACTION_TYPE_INSTANT_TETHERING = 10, - NP_FFI_BOOLEAN_ACTION_TYPE_PHONE_HUB = 11, - NP_FFI_BOOLEAN_ACTION_TYPE_PRESENCE_MANAGER = 12, - NP_FFI_BOOLEAN_ACTION_TYPE_FINDER = 13, - NP_FFI_BOOLEAN_ACTION_TYPE_FAST_PAIR_SASS = 14, -}; -typedef uint8_t np_ffi_BooleanActionType; - -/** - * Discriminant for `BuildContextSyncSeqNumResult`. - */ -enum np_ffi_BuildContextSyncSeqNumResultKind { - /** - * The sequence number was outside the allowed - * 0-15 single-nibble range. - */ - NP_FFI_BUILD_CONTEXT_SYNC_SEQ_NUM_RESULT_KIND_OUT_OF_RANGE = 0, - /** - * The sequence number was in range, - * and so a `ContextSyncSeqNum` was constructed. - */ - NP_FFI_BUILD_CONTEXT_SYNC_SEQ_NUM_RESULT_KIND_SUCCESS = 1, -}; -typedef uint8_t np_ffi_BuildContextSyncSeqNumResultKind; - -/** * Discriminant for `BuildTxPowerResult`. */ enum np_ffi_BuildTxPowerResultKind { @@ -219,73 +201,14 @@ */ NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_SUCCESS = 0, /** - * There was no space left to create a new credential book - */ - NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_NO_SPACE_LEFT = 1, - /** * The slab that we tried to create a credential-book from * actually was an invalid handle. */ - NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_INVALID_SLAB_HANDLE = 2, + NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_KIND_INVALID_SLAB_HANDLE = 1, }; typedef uint8_t np_ffi_CreateCredentialBookResultKind; /** - * Discriminant for `CreateCredentialSlabResult` - */ -enum np_ffi_CreateCredentialSlabResultKind { - /** - * There was no space left to create a new credential slab - */ - NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_KIND_NO_SPACE_LEFT = 0, - /** - * We created a new credential slab behind the given handle. - * The associated payload may be obtained via - * `CreateCredentialSlabResult#into_success()`. - */ - NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_KIND_SUCCESS = 1, -}; -typedef uint8_t np_ffi_CreateCredentialSlabResultKind; - -/** - * Discriminant for `CreateV0AdvertisementBuilderResult` - */ -enum np_ffi_CreateV0AdvertisementBuilderResultKind { - /** - * The attempt to create a new advertisement builder - * failed since there are no more available - * slots for V0 advertisement builders in their handle-map. - */ - NP_FFI_CREATE_V0_ADVERTISEMENT_BUILDER_RESULT_KIND_NO_SPACE_LEFT = 0, - /** - * The attempt succeeded. The wrapped advertisement builder - * may be obtained via - * `CreateV0AdvertisementBuilderResult#into_success`. - */ - NP_FFI_CREATE_V0_ADVERTISEMENT_BUILDER_RESULT_KIND_SUCCESS = 1, -}; -typedef uint8_t np_ffi_CreateV0AdvertisementBuilderResultKind; - -/** - * Discriminant for `CreateV1AdvertisementBuilderResult` - */ -enum np_ffi_CreateV1AdvertisementBuilderResultKind { - /** - * The attempt to create a new advertisement builder - * failed since there are no more available - * slots for V1 advertisement builders in their handle-map. - */ - NP_FFI_CREATE_V1_ADVERTISEMENT_BUILDER_RESULT_KIND_NO_SPACE_LEFT = 0, - /** - * The attempt succeeded. The wrapped advertisement builder - * may be obtained via - * `CreateV1AdvertisementBuilderResult#into_success`. - */ - NP_FFI_CREATE_V1_ADVERTISEMENT_BUILDER_RESULT_KIND_SUCCESS = 1, -}; -typedef uint8_t np_ffi_CreateV1AdvertisementBuilderResultKind; - -/** * Discriminant for `CreateV1SectionBuilderResult` */ enum np_ffi_CreateV1SectionBuilderResultKind { @@ -325,11 +248,11 @@ /** * The requested handle to deallocate was not present in the map */ - NP_FFI_DEALLOCATE_RESULT_NOT_PRESENT = 0, + NP_FFI_DEALLOCATE_RESULT_NOT_PRESENT = 1, /** * The object behind the handle was successfully deallocated */ - NP_FFI_DEALLOCATE_RESULT_SUCCESS = 1, + NP_FFI_DEALLOCATE_RESULT_SUCCESS = 2, } np_ffi_DeallocateResult; /** @@ -382,14 +305,14 @@ * The associated payload may be obtained via * `DeserializedV0Advertisement#into_legible`. */ - NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_LEGIBLE = 0, + NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_LEGIBLE = 1, /** * The deserialized V0 advertisement is illegible, * likely meaning that the receiver does not hold * the proper credentials to be able to read * the received advertisement. */ - NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_NO_MATCHING_CREDENTIALS = 1, + NP_FFI_DESERIALIZED_V0_ADVERTISEMENT_KIND_NO_MATCHING_CREDENTIALS = 2, }; typedef uint8_t np_ffi_DeserializedV0AdvertisementKind; @@ -401,11 +324,11 @@ /** * The deserialized identity was a plaintext identity. */ - NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_PLAINTEXT = 0, + NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_PLAINTEXT = 1, /** * The deserialized identity was some decrypted identity. */ - NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_DECRYPTED = 1, + NP_FFI_DESERIALIZED_V0_IDENTITY_KIND_DECRYPTED = 2, }; typedef uint8_t np_ffi_DeserializedV0IdentityKind; @@ -425,28 +348,6 @@ }; typedef uint8_t np_ffi_DeserializedV1IdentityKind; -/** - * The DE type for an encrypted identity - */ -enum np_ffi_EncryptedIdentityType { - /** - * Identity for broadcasts to nearby devices with the same - * logged-in-account (for some account). - */ - NP_FFI_ENCRYPTED_IDENTITY_TYPE_PRIVATE = 1, - /** - * Identity for broadcasts to nearby devices which this - * device has declared to trust. - */ - NP_FFI_ENCRYPTED_IDENTITY_TYPE_TRUSTED = 2, - /** - * Identity for broadcasts to devices which have been provisioned - * offline with this device. - */ - NP_FFI_ENCRYPTED_IDENTITY_TYPE_PROVISIONED = 4, -}; -typedef uint8_t np_ffi_EncryptedIdentityType; - enum np_ffi_GetMetadataBufferPartsResultKind { NP_FFI_GET_METADATA_BUFFER_PARTS_RESULT_KIND_SUCCESS = 0, NP_FFI_GET_METADATA_BUFFER_PARTS_RESULT_KIND_ERROR = 1, @@ -620,6 +521,12 @@ * in an entirely unexpected way. */ NP_FFI_PANIC_REASON_INVALID_STACK_DATA_STRUCTURE = 2, + /** + * The maximum amount of allocations per type is `u32::MAX`, this panic handler is invoked + * with this reason when this is exceeded. Clients should never need more than 4 Billions + * handles and would certainly run into other issues before reaching that point + */ + NP_FFI_PANIC_REASON_EXCEEDED_MAX_HANDLE_ALLOCATIONS = 3, }; typedef uint8_t np_ffi_PanicReason; @@ -632,16 +539,21 @@ */ NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_SUCCESS = 0, /** + * The advertisement builder handle was invalid. + */ + NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_INVALID_ADVERTISEMENT_BUILDER_HANDLE = 1, + /** * Serializing the advertisement to bytes failed * because the data in the advertisement wasn't * of an appropriate size for LDT encryption * to succeed. */ - NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_LDT_ERROR = 1, + NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_LDT_ERROR = 2, /** - * The advertisement builder handle was invalid. + * Serializing an unencrypted adv failed because the adv data didn't meet the length + * requirements. */ - NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_INVALID_ADVERTISEMENT_BUILDER_HANDLE = 2, + NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_KIND_UNENCRYPTED_ERROR = 3, }; typedef uint8_t np_ffi_SerializeV0AdvertisementResultKind; @@ -693,13 +605,13 @@ * The associated payload may be obtained via * `V0DataElement#into_tx_power`. */ - NP_FFI_V0_DATA_ELEMENT_KIND_TX_POWER = 0, + NP_FFI_V0_DATA_ELEMENT_KIND_TX_POWER = 1, /** * The Actions data-element. * The associated payload may be obtained via * `V0DataElement#into_actions`. */ - NP_FFI_V0_DATA_ELEMENT_KIND_ACTIONS = 1, + NP_FFI_V0_DATA_ELEMENT_KIND_ACTIONS = 2, }; typedef uint8_t np_ffi_V0DataElementKind; @@ -721,6 +633,19 @@ typedef uint8_t np_ffi_V1VerificationMode; /** + * Holds the count of handles currently allocated for each handle type + */ +typedef struct { + uint32_t cred_book; + uint32_t cred_slab; + uint32_t decrypted_metadata; + uint32_t v0_payload; + uint32_t legible_v1_sections; + uint32_t v0_advertisement_builder; + uint32_t v1_advertisement_builder; +} np_ffi_CurrentHandleAllocations; + +/** * A `#[repr(C)]` handle to a value of type `CredentialBookInternals` */ typedef struct { @@ -732,7 +657,6 @@ */ enum np_ffi_CreateCredentialBookResult_Tag { NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_SUCCESS = 0, - NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_NO_SPACE_LEFT = 1, NP_FFI_CREATE_CREDENTIAL_BOOK_RESULT_INVALID_SLAB_HANDLE = 2, }; typedef uint8_t np_ffi_CreateCredentialBookResult_Tag; @@ -753,29 +677,12 @@ } np_ffi_CredentialSlab; /** - * Result type for `create_credential_slab` - */ -typedef enum { - NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_NO_SPACE_LEFT, - NP_FFI_CREATE_CREDENTIAL_SLAB_RESULT_SUCCESS, -} np_ffi_CreateCredentialSlabResult_Tag; - -typedef struct { - np_ffi_CreateCredentialSlabResult_Tag tag; - union { - struct { - np_ffi_CredentialSlab success; - }; - }; -} np_ffi_CreateCredentialSlabResult; - -/** * Cryptographic information about a particular V0 discovery credential * necessary to match and decrypt encrypted V0 advertisements. */ typedef struct { uint8_t key_seed[32]; - uint8_t legacy_metadata_key_hmac[32]; + uint8_t identity_token_hmac[32]; } np_ffi_V0DiscoveryCredential; /** @@ -803,8 +710,9 @@ */ typedef struct { uint8_t key_seed[32]; - uint8_t expected_unsigned_metadata_key_hmac[32]; - uint8_t expected_signed_metadata_key_hmac[32]; + uint8_t expected_mic_short_salt_identity_token_hmac[32]; + uint8_t expected_mic_extended_salt_identity_token_hmac[32]; + uint8_t expected_signature_identity_token_hmac[32]; uint8_t pub_key[32]; } np_ffi_V1DiscoveryCredential; @@ -908,8 +816,17 @@ * Representation of a deserialized V1 advertisement */ typedef struct { + /** + * The number of legible sections + */ uint8_t num_legible_sections; + /** + * The number of sections that were unable to be decrypted + */ uint8_t num_undecryptable_sections; + /** + * A handle to the set of legible (plain or decrypted) sections + */ np_ffi_LegibleV1Sections legible_sections; } np_ffi_DeserializedV1Advertisement; @@ -977,7 +894,7 @@ } np_ffi_TxPower; /** - * The bitfield data of a VOActions data element + * The bitfield data of a V0Actions data element */ typedef struct { uint32_t bitfield; @@ -1052,18 +969,14 @@ */ typedef struct { /** - * The identity type (private/provisioned/trusted) - */ - np_ffi_EncryptedIdentityType identity_type; - /** * The ID of the credential which * matched the deserialized adv */ uint32_t cred_id; /** - * The 14-byte legacy metadata key + * The 14-byte legacy identity token */ - uint8_t metadata_key[14]; + uint8_t identity_token[14]; /** * The 2-byte advertisement salt */ @@ -1202,10 +1115,6 @@ */ typedef struct { /** - * The identity type (private/provisioned/trusted) - */ - np_ffi_EncryptedIdentityType identity_type; - /** * The verification mode (MIC/Signature) which * was used to verify the decrypted adv contents. */ @@ -1218,7 +1127,7 @@ /** * The 16-byte metadata key. */ - uint8_t metadata_key[16]; + uint8_t identity_token[16]; } np_ffi_DeserializedV1IdentityDetails; /** @@ -1297,8 +1206,9 @@ */ typedef enum { NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_SUCCESS, - NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_LDT_ERROR, NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_INVALID_ADVERTISEMENT_BUILDER_HANDLE, + NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_LDT_ERROR, + NP_FFI_SERIALIZE_V0_ADVERTISEMENT_RESULT_UNENCRYPTED_ERROR, } np_ffi_SerializeV0AdvertisementResult_Tag; typedef struct { @@ -1311,29 +1221,12 @@ } np_ffi_SerializeV0AdvertisementResult; /** - * The result of attempting to create a new V0 advertisement builder. - */ -typedef enum { - NP_FFI_CREATE_V0_ADVERTISEMENT_BUILDER_RESULT_NO_SPACE_LEFT, - NP_FFI_CREATE_V0_ADVERTISEMENT_BUILDER_RESULT_SUCCESS, -} np_ffi_CreateV0AdvertisementBuilderResult_Tag; - -typedef struct { - np_ffi_CreateV0AdvertisementBuilderResult_Tag tag; - union { - struct { - np_ffi_V0AdvertisementBuilder success; - }; - }; -} np_ffi_CreateV0AdvertisementBuilderResult; - -/** * Cryptographic information about a particular V0 broadcast credential * necessary to LDT-encrypt V0 advertisements. */ typedef struct { uint8_t key_seed[32]; - uint8_t metadata_key[14]; + uint8_t identity_token[14]; } np_ffi_V0BroadcastCredential; /** @@ -1359,7 +1252,8 @@ } np_ffi_V1AdvertisementBuilder; /** - * A handle to a builder for V1 sections. + * A handle to a builder for V1 sections. This is not a unique handle; it is the same handle as + * the advertisement builder the section builder was originated from. */ typedef struct { np_ffi_V1AdvertisementBuilder adv_builder; @@ -1392,7 +1286,7 @@ */ typedef struct { uint8_t key_seed[32]; - uint8_t metadata_key[16]; + uint8_t identity_token[16]; uint8_t private_key[32]; } np_ffi_V1BroadcastCredential; @@ -1427,23 +1321,6 @@ } np_ffi_SerializeV1AdvertisementResult; /** - * The result of attempting to create a new V1 advertisement builder. - */ -typedef enum { - NP_FFI_CREATE_V1_ADVERTISEMENT_BUILDER_RESULT_NO_SPACE_LEFT, - NP_FFI_CREATE_V1_ADVERTISEMENT_BUILDER_RESULT_SUCCESS, -} np_ffi_CreateV1AdvertisementBuilderResult_Tag; - -typedef struct { - np_ffi_CreateV1AdvertisementBuilderResult_Tag tag; - union { - struct { - np_ffi_V1AdvertisementBuilder success; - }; - }; -} np_ffi_CreateV1AdvertisementBuilderResult; - -/** * The result of attempting to get the derived V1 DE * 16-byte salt for the next-added DE to the section * builder behind the given handle. @@ -1522,31 +1399,6 @@ } np_ffi_SetV0ActionResult; /** - * Representation of a context-sync sequence number. - */ -typedef struct { - uint8_t value; -} np_ffi_ContextSyncSeqNum; - -/** - * Result type for attempting to construct a - * ContextSyncSeqNum from an unsigned byte. - */ -typedef enum { - NP_FFI_BUILD_CONTEXT_SYNC_SEQ_NUM_RESULT_OUT_OF_RANGE, - NP_FFI_BUILD_CONTEXT_SYNC_SEQ_NUM_RESULT_SUCCESS, -} np_ffi_BuildContextSyncSeqNumResult_Tag; - -typedef struct { - np_ffi_BuildContextSyncSeqNumResult_Tag tag; - union { - struct { - np_ffi_ContextSyncSeqNum success; - }; - }; -} np_ffi_BuildContextSyncSeqNumResult; - -/** * Overrides the global panic handler to be used when NP C FFI calls panic. * This method will only have an effect on the global panic-handler * the first time it's called, and this method will return `true` @@ -1569,6 +1421,12 @@ bool np_ffi_global_config_panic_handler(void (*handler)(np_ffi_PanicReason)); /** + * Checks the current count of all outstanding handle allocations, useful for debugging, + * logging, and testing + */ +np_ffi_CurrentHandleAllocations np_ffi_global_config_get_current_allocation_count(void); + +/** * Sets an override to the number of shards to employ in the NP FFI's * internal handle-maps, which places an upper bound on the number * of writing threads which may make progress at any one time @@ -1587,106 +1445,6 @@ void np_ffi_global_config_set_num_shards(uint8_t num_shards); /** - * Sets the maximum number of active handles to credential slabs - * which may be active at any one time. - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Useful for bounding the maximum memory used by the client application - * on credential slabs in constrained-memory environments. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call utilizing credential slabs. - */ -void np_ffi_global_config_set_max_num_credential_slabs(uint32_t max_num_credential_slabs); - -/** - * Sets the maximum number of active handles to credential books - * which may be active at any one time. - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Useful for bounding the maximum memory used by the client application - * on credential books in constrained-memory environments. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call utilizing credential books. - */ -void np_ffi_global_config_set_max_num_credential_books(uint32_t max_num_credential_books); - -/** - * Sets the maximum number of active handles to deserialized v0 - * advertisements which may be active at any one time. - * - * Useful for bounding the maximum memory used by the client application - * on v0 advertisements in constrained-memory environments. - * - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call which references or returns a deserialized V0 advertisement. - */ -void np_ffi_global_config_set_max_num_deserialized_v0_advertisements(uint32_t max_num_deserialized_v0_advertisements); - -/** - * Sets the maximum number of active handles to deserialized v1 - * advertisements which may be active at any one time. - * - * Useful for bounding the maximum memory used by the client application - * on v1 advertisements in constrained-memory environments. - * - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call which references or returns a deserialized V1 advertisement. - */ -void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements); - -/** - * Sets the maximum number of active handles to v0 advertisement - * builders which may be active at any one time. - * - * Useful for bounding the maximum memory used by the client application - * on v0 advertisements in constrained-memory environments. - * - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call which references or returns a V0 advertisement builder. - */ -void np_ffi_global_config_set_max_num_v0_advertisement_builders(uint32_t max_num_v0_advertisement_builders); - -/** - * Sets the maximum number of active handles to v1 advertisement - * builders which may be active at any one time. - * - * Useful for bounding the maximum memory used by the client application - * on v1 advertisements in constrained-memory environments. - * - * Default value: Max value. - * Max value: `u32::MAX - 1`. - * - * Setting this value will have no effect if the handle-maps for the - * API have already begun being used by the client code, and any - * values set will take effect upon the first usage of any API - * call which references or returns a V1 advertisement builder. - */ -void np_ffi_global_config_set_max_num_v1_advertisement_builders(uint32_t max_num_v1_advertisement_builders); - -/** * Allocates a new credential-book from the given slab, returning a handle * to the created object. The slab will be deallocated by this call. */ @@ -1716,18 +1474,7 @@ /** * Allocates a new credential-slab, returning a handle to the created object */ -np_ffi_CreateCredentialSlabResult np_ffi_create_credential_slab(void); - -/** - * Gets the tag of a `CreateCredentialSlabResult` tagged enum. - */ -np_ffi_CreateCredentialSlabResultKind np_ffi_CreateCredentialSlabResult_kind(np_ffi_CreateCredentialSlabResult result); - -/** - * Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the - * case where the passed value is of a different enum variant. - */ -np_ffi_CredentialSlab np_ffi_CreateCredentialSlabResult_into_SUCCESS(np_ffi_CreateCredentialSlabResult result); +np_ffi_CredentialSlab np_ffi_create_credential_slab(void); /** * Adds the given V0 discovery credential with some associated @@ -2033,27 +1780,15 @@ np_ffi_DeallocateResult np_ffi_deallocate_v0_advertisement_builder(np_ffi_V0AdvertisementBuilder adv_builder); /** - * Gets the tag of a `CreateV0AdvertisementBuilderResult` tagged-union. - */ -np_ffi_CreateV0AdvertisementBuilderResultKind np_ffi_CreateV0AdvertisementBuilderResult_kind(np_ffi_CreateV0AdvertisementBuilderResult result); - -/** - * Casts a `CreateV0AdvertisementBuilderResult` to the `Success` variant, - * panicking in the case where the passed value is of a different enum variant. - */ -np_ffi_V0AdvertisementBuilder np_ffi_CreateV0AdvertisementBuilderResult_into_SUCCESS(np_ffi_CreateV0AdvertisementBuilderResult result); - -/** * Creates a new V0 advertisement builder for a public advertisement. */ -np_ffi_CreateV0AdvertisementBuilderResult np_ffi_create_v0_public_advertisement_builder(void); +np_ffi_V0AdvertisementBuilder np_ffi_create_v0_public_advertisement_builder(void); /** * Creates a new V0 advertisement builder for an encrypted advertisement. */ -np_ffi_CreateV0AdvertisementBuilderResult np_ffi_create_v0_encrypted_advertisement_builder(np_ffi_V0BroadcastCredential broadcast_cred, - np_ffi_EncryptedIdentityType identity_type, - np_ffi_FixedSizeArray_2 salt); +np_ffi_V0AdvertisementBuilder np_ffi_create_v0_encrypted_advertisement_builder(np_ffi_V0BroadcastCredential broadcast_cred, + np_ffi_FixedSizeArray_2 salt); /** * Gets the tag of a `SerializeV0AdvertisementResult` tagged-union. @@ -2097,7 +1832,6 @@ */ np_ffi_CreateV1SectionBuilderResult np_ffi_V1AdvertisementBuilder_encrypted_section_builder(np_ffi_V1AdvertisementBuilder adv_builder, np_ffi_V1BroadcastCredential broadcast_cred, - np_ffi_EncryptedIdentityType identity_type, np_ffi_V1VerificationMode verification_mode); /** @@ -2109,21 +1843,10 @@ np_ffi_SerializeV1AdvertisementResult np_ffi_V1AdvertisementBuilder_into_advertisement(np_ffi_V1AdvertisementBuilder adv_builder); /** - * Gets the tag of a `CreateV1AdvertisementBuilderResult` tagged-union. - */ -np_ffi_CreateV1AdvertisementBuilderResultKind np_ffi_CreateV1AdvertisementBuilderResult_kind(np_ffi_CreateV1AdvertisementBuilderResult result); - -/** - * Casts a `CreateV1AdvertisementBuilderResult` to the `Success` variant, - * panicking in the case where the passed value is of a different enum variant. - */ -np_ffi_V1AdvertisementBuilder np_ffi_CreateV1AdvertisementBuilderResult_into_SUCCESS(np_ffi_CreateV1AdvertisementBuilderResult result); - -/** * Creates a new V1 advertisement builder for the given advertisement * kind (public/encrypted). */ -np_ffi_CreateV1AdvertisementBuilderResult np_ffi_create_v1_advertisement_builder(np_ffi_AdvertisementBuilderKind kind); +np_ffi_V1AdvertisementBuilder np_ffi_create_v1_advertisement_builder(np_ffi_AdvertisementBuilderKind kind); /** * Gets the tag of a `SerializeV1AdvertisementResult` tagged-union. @@ -2256,12 +1979,7 @@ /** * Return whether a boolean action type is set in this data element */ -bool np_ffi_V0Actions_has_action(np_ffi_V0Actions actions, np_ffi_BooleanActionType action_type); - -/** - * Gets the 4 bit context sync sequence number as a u8 from this data element - */ -np_ffi_ContextSyncSeqNum np_ffi_V0Actions_get_context_sync_sequence_number(np_ffi_V0Actions actions); +bool np_ffi_V0Actions_has_action(np_ffi_V0Actions actions, np_ffi_ActionType action_type); /** * Attempts to set the given action bit to the given boolean value. @@ -2272,44 +1990,16 @@ * unaltered. */ np_ffi_SetV0ActionResult np_ffi_V0Actions_set_action(np_ffi_V0Actions actions, - np_ffi_BooleanActionType action_type, + np_ffi_ActionType action_type, bool value); /** - * Sets the context sequence number for the given Actions DE. - */ -np_ffi_V0Actions np_ffi_V0Actions_set_context_sync_sequence_number(np_ffi_V0Actions actions, - np_ffi_ContextSyncSeqNum value); - -/** * Returns the representation of the passed `V0Actions` as an unsigned * integer, where the bit-positions correspond to individual actions. */ uint32_t np_ffi_V0Actions_as_u32(np_ffi_V0Actions actions); /** - * Gets the tag of a `BuildContextSyncSeqNumResult` tagged-union. - */ -np_ffi_BuildContextSyncSeqNumResultKind np_ffi_BuildContextSyncSeqNumResult_kind(np_ffi_BuildContextSyncSeqNumResult result); - -/** - * Casts a `BuildContextSyncSeqNumResult` to the `Success` variant, panicking in the - * case where the passed value is of a different enum variant. - */ -np_ffi_ContextSyncSeqNum np_ffi_BuildContextSyncSeqNumResult_into_SUCCESS(np_ffi_BuildContextSyncSeqNumResult result); - -/** - * Attempts to build a new context sync sequence number - * from the given unsigned byte. - */ -np_ffi_BuildContextSyncSeqNumResult np_ffi_ContextSyncSeqNum_build_from_unsigned_byte(uint8_t value); - -/** - * Gets the value of the given context-sync sequence number as an unsigned byte. - */ -uint8_t np_ffi_ContextSyncSeqNum_as_unsigned_byte(np_ffi_ContextSyncSeqNum seq_num); - -/** * Converts a `V1DataElement` to a `GenericV1DataElement` which * only maintains information about the DE's type-code and payload. */
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h index 51322d3..d197bc8 100644 --- a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h +++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_functions.h
@@ -61,6 +61,10 @@ /// but a bare `loop { }` when this crate is compiled without. bool np_ffi_global_config_panic_handler(void (*handler)(PanicReason)); +/// Checks the current count of all outstanding handle allocations, useful for debugging, +/// logging, and testing +CurrentHandleAllocations np_ffi_global_config_get_current_allocation_count(); + /// Sets an override to the number of shards to employ in the NP FFI's /// internal handle-maps, which places an upper bound on the number /// of writing threads which may make progress at any one time @@ -77,94 +81,6 @@ /// API call. void np_ffi_global_config_set_num_shards(uint8_t num_shards); -/// Sets the maximum number of active handles to credential slabs -/// which may be active at any one time. -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Useful for bounding the maximum memory used by the client application -/// on credential slabs in constrained-memory environments. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential slabs. -void np_ffi_global_config_set_max_num_credential_slabs(uint32_t max_num_credential_slabs); - -/// Sets the maximum number of active handles to credential books -/// which may be active at any one time. -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Useful for bounding the maximum memory used by the client application -/// on credential books in constrained-memory environments. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential books. -void np_ffi_global_config_set_max_num_credential_books(uint32_t max_num_credential_books); - -/// Sets the maximum number of active handles to deserialized v0 -/// advertisements which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v0 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V0 advertisement. -void np_ffi_global_config_set_max_num_deserialized_v0_advertisements(uint32_t max_num_deserialized_v0_advertisements); - -/// Sets the maximum number of active handles to deserialized v1 -/// advertisements which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v1 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V1 advertisement. -void np_ffi_global_config_set_max_num_deserialized_v1_advertisements(uint32_t max_num_deserialized_v1_advertisements); - -/// Sets the maximum number of active handles to v0 advertisement -/// builders which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v0 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a V0 advertisement builder. -void np_ffi_global_config_set_max_num_v0_advertisement_builders(uint32_t max_num_v0_advertisement_builders); - -/// Sets the maximum number of active handles to v1 advertisement -/// builders which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v1 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a V1 advertisement builder. -void np_ffi_global_config_set_max_num_v1_advertisement_builders(uint32_t max_num_v1_advertisement_builders); - /// Allocates a new credential-book from the given slab, returning a handle /// to the created object. The slab will be deallocated by this call. CreateCredentialBookResult np_ffi_create_credential_book_from_slab(CredentialSlab slab); @@ -183,14 +99,7 @@ DeallocateResult np_ffi_deallocate_credential_book(CredentialBook credential_book); /// Allocates a new credential-slab, returning a handle to the created object -CreateCredentialSlabResult np_ffi_create_credential_slab(); - -/// Gets the tag of a `CreateCredentialSlabResult` tagged enum. -CreateCredentialSlabResultKind np_ffi_CreateCredentialSlabResult_kind(CreateCredentialSlabResult result); - -/// Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the -/// case where the passed value is of a different enum variant. -CredentialSlab np_ffi_CreateCredentialSlabResult_into_SUCCESS(CreateCredentialSlabResult result); +CredentialSlab np_ffi_create_credential_slab(); /// Adds the given V0 discovery credential with some associated /// match-data to this credential slab. @@ -396,20 +305,12 @@ /// the given handle. DeallocateResult np_ffi_deallocate_v0_advertisement_builder(V0AdvertisementBuilder adv_builder); -/// Gets the tag of a `CreateV0AdvertisementBuilderResult` tagged-union. -CreateV0AdvertisementBuilderResultKind np_ffi_CreateV0AdvertisementBuilderResult_kind(CreateV0AdvertisementBuilderResult result); - -/// Casts a `CreateV0AdvertisementBuilderResult` to the `Success` variant, -/// panicking in the case where the passed value is of a different enum variant. -V0AdvertisementBuilder np_ffi_CreateV0AdvertisementBuilderResult_into_SUCCESS(CreateV0AdvertisementBuilderResult result); - /// Creates a new V0 advertisement builder for a public advertisement. -CreateV0AdvertisementBuilderResult np_ffi_create_v0_public_advertisement_builder(); +V0AdvertisementBuilder np_ffi_create_v0_public_advertisement_builder(); /// Creates a new V0 advertisement builder for an encrypted advertisement. -CreateV0AdvertisementBuilderResult np_ffi_create_v0_encrypted_advertisement_builder(V0BroadcastCredential broadcast_cred, - EncryptedIdentityType identity_type, - FixedSizeArray<2> salt); +V0AdvertisementBuilder np_ffi_create_v0_encrypted_advertisement_builder(V0BroadcastCredential broadcast_cred, + FixedSizeArray<2> salt); /// Gets the tag of a `SerializeV0AdvertisementResult` tagged-union. SerializeV0AdvertisementResultKind np_ffi_SerializeV0AdvertisementResult_kind(SerializeV0AdvertisementResult result); @@ -445,7 +346,6 @@ /// to fit within the enclosing advertisement. CreateV1SectionBuilderResult np_ffi_V1AdvertisementBuilder_encrypted_section_builder(V1AdvertisementBuilder adv_builder, V1BroadcastCredential broadcast_cred, - EncryptedIdentityType identity_type, V1VerificationMode verification_mode); /// Attempts to serialize the contents of the advertisement builder @@ -454,16 +354,9 @@ /// advertisement builder handle being deallocated. SerializeV1AdvertisementResult np_ffi_V1AdvertisementBuilder_into_advertisement(V1AdvertisementBuilder adv_builder); -/// Gets the tag of a `CreateV1AdvertisementBuilderResult` tagged-union. -CreateV1AdvertisementBuilderResultKind np_ffi_CreateV1AdvertisementBuilderResult_kind(CreateV1AdvertisementBuilderResult result); - -/// Casts a `CreateV1AdvertisementBuilderResult` to the `Success` variant, -/// panicking in the case where the passed value is of a different enum variant. -V1AdvertisementBuilder np_ffi_CreateV1AdvertisementBuilderResult_into_SUCCESS(CreateV1AdvertisementBuilderResult result); - /// Creates a new V1 advertisement builder for the given advertisement /// kind (public/encrypted). -CreateV1AdvertisementBuilderResult np_ffi_create_v1_advertisement_builder(AdvertisementBuilderKind kind); +V1AdvertisementBuilder np_ffi_create_v1_advertisement_builder(AdvertisementBuilderKind kind); /// Gets the tag of a `SerializeV1AdvertisementResult` tagged-union. SerializeV1AdvertisementResultKind np_ffi_SerializeV1AdvertisementResult_kind(SerializeV1AdvertisementResult result); @@ -550,10 +443,7 @@ V0Actions np_ffi_build_new_zeroed_V0Actions(AdvertisementBuilderKind kind); /// Return whether a boolean action type is set in this data element -bool np_ffi_V0Actions_has_action(V0Actions actions, BooleanActionType action_type); - -/// Gets the 4 bit context sync sequence number as a u8 from this data element -ContextSyncSeqNum np_ffi_V0Actions_get_context_sync_sequence_number(V0Actions actions); +bool np_ffi_V0Actions_has_action(V0Actions actions, ActionType action_type); /// Attempts to set the given action bit to the given boolean value. /// This operation may fail if the requested action bit may not be @@ -562,31 +452,13 @@ /// the original action bits will be yielded back to the caller, /// unaltered. SetV0ActionResult np_ffi_V0Actions_set_action(V0Actions actions, - BooleanActionType action_type, + ActionType action_type, bool value); -/// Sets the context sequence number for the given Actions DE. -V0Actions np_ffi_V0Actions_set_context_sync_sequence_number(V0Actions actions, - ContextSyncSeqNum value); - /// Returns the representation of the passed `V0Actions` as an unsigned /// integer, where the bit-positions correspond to individual actions. uint32_t np_ffi_V0Actions_as_u32(V0Actions actions); -/// Gets the tag of a `BuildContextSyncSeqNumResult` tagged-union. -BuildContextSyncSeqNumResultKind np_ffi_BuildContextSyncSeqNumResult_kind(BuildContextSyncSeqNumResult result); - -/// Casts a `BuildContextSyncSeqNumResult` to the `Success` variant, panicking in the -/// case where the passed value is of a different enum variant. -ContextSyncSeqNum np_ffi_BuildContextSyncSeqNumResult_into_SUCCESS(BuildContextSyncSeqNumResult result); - -/// Attempts to build a new context sync sequence number -/// from the given unsigned byte. -BuildContextSyncSeqNumResult np_ffi_ContextSyncSeqNum_build_from_unsigned_byte(uint8_t value); - -/// Gets the value of the given context-sync sequence number as an unsigned byte. -uint8_t np_ffi_ContextSyncSeqNum_as_unsigned_byte(ContextSyncSeqNum seq_num); - /// Converts a `V1DataElement` to a `GenericV1DataElement` which /// only maintains information about the DE's type-code and payload. GenericV1DataElement np_ffi_V1DataElement_to_generic(V1DataElement de);
diff --git a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h index 5e4e5a2..ba3ed34 100644 --- a/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h +++ b/nearby/presence/np_c_ffi/include/cpp/np_cpp_ffi_types.h
@@ -38,6 +38,16 @@ namespace np_ffi { namespace internal { +/// The possible boolean action types which can be present in an Actions data element +enum class ActionType : uint8_t { + CrossDevSdk = 1, + CallTransfer = 4, + ActiveUnlock = 8, + NearbyShare = 9, + InstantTethering = 10, + PhoneHub = 11, +}; + /// Result type for trying to add a V0 credential to a credential-slab. enum class AddV0CredentialToSlabResult : uint8_t { /// We succeeded in adding the credential to the slab. @@ -112,27 +122,6 @@ Encrypted = 1, }; -/// The possible boolean action types which can be present in an Actions data element -enum class BooleanActionType : uint8_t { - ActiveUnlock = 8, - NearbyShare = 9, - InstantTethering = 10, - PhoneHub = 11, - PresenceManager = 12, - Finder = 13, - FastPairSass = 14, -}; - -/// Discriminant for `BuildContextSyncSeqNumResult`. -enum class BuildContextSyncSeqNumResultKind : uint8_t { - /// The sequence number was outside the allowed - /// 0-15 single-nibble range. - OutOfRange = 0, - /// The sequence number was in range, - /// and so a `ContextSyncSeqNum` was constructed. - Success = 1, -}; - /// Discriminant for `BuildTxPowerResult`. enum class BuildTxPowerResultKind : uint8_t { /// The transmission power was outside the @@ -149,45 +138,9 @@ /// The associated payload may be obtained via /// `CreateCredentialBookResult#into_success()`. Success = 0, - /// There was no space left to create a new credential book - NoSpaceLeft = 1, /// The slab that we tried to create a credential-book from /// actually was an invalid handle. - InvalidSlabHandle = 2, -}; - -/// Discriminant for `CreateCredentialSlabResult` -enum class CreateCredentialSlabResultKind : uint8_t { - /// There was no space left to create a new credential slab - NoSpaceLeft = 0, - /// We created a new credential slab behind the given handle. - /// The associated payload may be obtained via - /// `CreateCredentialSlabResult#into_success()`. - Success = 1, -}; - -/// Discriminant for `CreateV0AdvertisementBuilderResult` -enum class CreateV0AdvertisementBuilderResultKind : uint8_t { - /// The attempt to create a new advertisement builder - /// failed since there are no more available - /// slots for V0 advertisement builders in their handle-map. - NoSpaceLeft = 0, - /// The attempt succeeded. The wrapped advertisement builder - /// may be obtained via - /// `CreateV0AdvertisementBuilderResult#into_success`. - Success = 1, -}; - -/// Discriminant for `CreateV1AdvertisementBuilderResult` -enum class CreateV1AdvertisementBuilderResultKind : uint8_t { - /// The attempt to create a new advertisement builder - /// failed since there are no more available - /// slots for V1 advertisement builders in their handle-map. - NoSpaceLeft = 0, - /// The attempt succeeded. The wrapped advertisement builder - /// may be obtained via - /// `CreateV1AdvertisementBuilderResult#into_success`. - Success = 1, + InvalidSlabHandle = 1, }; /// Discriminant for `CreateV1SectionBuilderResult` @@ -213,9 +166,9 @@ /// succeeded or failed due to the requested handle not being present. enum class DeallocateResult { /// The requested handle to deallocate was not present in the map - NotPresent = 0, + NotPresent = 1, /// The object behind the handle was successfully deallocated - Success = 1, + Success = 2, }; /// Discriminant for `DecryptMetadataResult`. @@ -248,21 +201,21 @@ /// The deserialized V0 advertisement was legible. /// The associated payload may be obtained via /// `DeserializedV0Advertisement#into_legible`. - Legible = 0, + Legible = 1, /// The deserialized V0 advertisement is illegible, /// likely meaning that the receiver does not hold /// the proper credentials to be able to read /// the received advertisement. - NoMatchingCredentials = 1, + NoMatchingCredentials = 2, }; /// Discriminant for deserialized information about the V0 /// identity utilized by a deserialized V0 advertisement. enum class DeserializedV0IdentityKind : uint8_t { /// The deserialized identity was a plaintext identity. - Plaintext = 0, + Plaintext = 1, /// The deserialized identity was some decrypted identity. - Decrypted = 1, + Decrypted = 2, }; /// Discriminant for `DeserializedV1Identity`. @@ -274,19 +227,6 @@ Decrypted = 1, }; -/// The DE type for an encrypted identity -enum class EncryptedIdentityType : uint8_t { - /// Identity for broadcasts to nearby devices with the same - /// logged-in-account (for some account). - Private = 1, - /// Identity for broadcasts to nearby devices which this - /// device has declared to trust. - Trusted = 2, - /// Identity for broadcasts to devices which have been provisioned - /// offline with this device. - Provisioned = 4, -}; - enum class GetMetadataBufferPartsResultKind : uint8_t { Success = 0, Error = 1, @@ -402,19 +342,26 @@ /// be messing with stack-allocated data structures for this library /// in an entirely unexpected way. InvalidStackDataStructure = 2, + /// The maximum amount of allocations per type is `u32::MAX`, this panic handler is invoked + /// with this reason when this is exceeded. Clients should never need more than 4 Billions + /// handles and would certainly run into other issues before reaching that point + ExceededMaxHandleAllocations = 3, }; /// Discriminant for `SerializeV0AdvertisementResult`. enum class SerializeV0AdvertisementResultKind : uint8_t { /// Serializing the advertisement to bytes was successful. Success = 0, + /// The advertisement builder handle was invalid. + InvalidAdvertisementBuilderHandle = 1, /// Serializing the advertisement to bytes failed /// because the data in the advertisement wasn't /// of an appropriate size for LDT encryption /// to succeed. - LdtError = 1, - /// The advertisement builder handle was invalid. - InvalidAdvertisementBuilderHandle = 2, + LdtError = 2, + /// Serializing an unencrypted adv failed because the adv data didn't meet the length + /// requirements. + UnencryptedError = 3, }; /// Discriminant for `SerializeV1AdvertisementResult`. @@ -445,11 +392,11 @@ /// A transmission Power (Tx Power) data-element. /// The associated payload may be obtained via /// `V0DataElement#into_tx_power`. - TxPower = 0, + TxPower = 1, /// The Actions data-element. /// The associated payload may be obtained via /// `V0DataElement#into_actions`. - Actions = 1, + Actions = 2, }; /// Information about the verification scheme used @@ -462,6 +409,17 @@ Signature = 1, }; +/// Holds the count of handles currently allocated for each handle type +struct CurrentHandleAllocations { + uint32_t cred_book; + uint32_t cred_slab; + uint32_t decrypted_metadata; + uint32_t v0_payload; + uint32_t legible_v1_sections; + uint32_t v0_advertisement_builder; + uint32_t v1_advertisement_builder; +}; + /// A `#[repr(C)]` handle to a value of type `CredentialBookInternals` struct CredentialBook { uint64_t handle_id; @@ -471,7 +429,6 @@ union CreateCredentialBookResult { enum class Tag : uint8_t { Success = 0, - NoSpaceLeft = 1, InvalidSlabHandle = 2, }; @@ -491,28 +448,11 @@ uint64_t handle_id; }; -/// Result type for `create_credential_slab` -struct CreateCredentialSlabResult { - enum class Tag { - NoSpaceLeft, - Success, - }; - - struct Success_Body { - CredentialSlab _0; - }; - - Tag tag; - union { - Success_Body success; - }; -}; - /// Cryptographic information about a particular V0 discovery credential /// necessary to match and decrypt encrypted V0 advertisements. struct V0DiscoveryCredential { uint8_t key_seed[32]; - uint8_t legacy_metadata_key_hmac[32]; + uint8_t identity_token_hmac[32]; }; /// A representation of a MatchedCredential which is passable across the FFI boundary @@ -534,8 +474,9 @@ /// necessary to match and decrypt encrypted V1 advertisement sections. struct V1DiscoveryCredential { uint8_t key_seed[32]; - uint8_t expected_unsigned_metadata_key_hmac[32]; - uint8_t expected_signed_metadata_key_hmac[32]; + uint8_t expected_mic_short_salt_identity_token_hmac[32]; + uint8_t expected_mic_extended_salt_identity_token_hmac[32]; + uint8_t expected_signature_identity_token_hmac[32]; uint8_t pub_key[32]; }; @@ -627,8 +568,11 @@ /// Representation of a deserialized V1 advertisement struct DeserializedV1Advertisement { + /// The number of legible sections uint8_t num_legible_sections; + /// The number of sections that were unable to be decrypted uint8_t num_undecryptable_sections; + /// A handle to the set of legible (plain or decrypted) sections LegibleV1Sections legible_sections; }; @@ -687,7 +631,7 @@ int8_t tx_power; }; -/// The bitfield data of a VOActions data element +/// The bitfield data of a V0Actions data element struct V0ActionBits { uint32_t bitfield; }; @@ -758,13 +702,11 @@ /// Information about the identity which matched a /// decrypted V0 advertisement. struct DeserializedV0IdentityDetails { - /// The identity type (private/provisioned/trusted) - EncryptedIdentityType identity_type; /// The ID of the credential which /// matched the deserialized adv uint32_t cred_id; - /// The 14-byte legacy metadata key - uint8_t metadata_key[14]; + /// The 14-byte legacy identity token + uint8_t identity_token[14]; /// The 2-byte advertisement salt uint8_t salt[2]; }; @@ -873,8 +815,6 @@ /// Information about the identity which matched /// a decrypted V1 section. struct DeserializedV1IdentityDetails { - /// The identity type (private/provisioned/trusted) - EncryptedIdentityType identity_type; /// The verification mode (MIC/Signature) which /// was used to verify the decrypted adv contents. V1VerificationMode verification_mode; @@ -882,7 +822,7 @@ /// matched the deserialized section. uint32_t cred_id; /// The 16-byte metadata key. - uint8_t metadata_key[16]; + uint8_t identity_token[16]; }; /// The result of attempting to get the identity details @@ -944,8 +884,9 @@ struct SerializeV0AdvertisementResult { enum class Tag { Success, - LdtError, InvalidAdvertisementBuilderHandle, + LdtError, + UnencryptedError, }; struct Success_Body { @@ -958,28 +899,11 @@ }; }; -/// The result of attempting to create a new V0 advertisement builder. -struct CreateV0AdvertisementBuilderResult { - enum class Tag { - NoSpaceLeft, - Success, - }; - - struct Success_Body { - V0AdvertisementBuilder _0; - }; - - Tag tag; - union { - Success_Body success; - }; -}; - /// Cryptographic information about a particular V0 broadcast credential /// necessary to LDT-encrypt V0 advertisements. struct V0BroadcastCredential { uint8_t key_seed[32]; - uint8_t metadata_key[14]; + uint8_t identity_token[14]; }; /// A `#[repr(C)]` handle to a value of type `V1AdvertisementBuilderInternals` @@ -993,7 +917,8 @@ V1AdvertisementBuilderHandle handle; }; -/// A handle to a builder for V1 sections. +/// A handle to a builder for V1 sections. This is not a unique handle; it is the same handle as +/// the advertisement builder the section builder was originated from. struct V1SectionBuilder { V1AdvertisementBuilder adv_builder; uint8_t section_index; @@ -1023,7 +948,7 @@ /// necessary to encrypt V1 MIC-verified and signature-verified sections. struct V1BroadcastCredential { uint8_t key_seed[32]; - uint8_t metadata_key[16]; + uint8_t identity_token[16]; uint8_t private_key[32]; }; @@ -1046,23 +971,6 @@ }; }; -/// The result of attempting to create a new V1 advertisement builder. -struct CreateV1AdvertisementBuilderResult { - enum class Tag { - NoSpaceLeft, - Success, - }; - - struct Success_Body { - V1AdvertisementBuilder _0; - }; - - Tag tag; - union { - Success_Body success; - }; -}; - /// The result of attempting to get the derived V1 DE /// 16-byte salt for the next-added DE to the section /// builder behind the given handle. @@ -1137,29 +1045,6 @@ }; }; -/// Representation of a context-sync sequence number. -struct ContextSyncSeqNum { - uint8_t value; -}; - -/// Result type for attempting to construct a -/// ContextSyncSeqNum from an unsigned byte. -struct BuildContextSyncSeqNumResult { - enum class Tag { - OutOfRange, - Success, - }; - - struct Success_Body { - ContextSyncSeqNum _0; - }; - - Tag tag; - union { - Success_Body success; - }; -}; - } // namespace internal } // namespace np_ffi
diff --git a/nearby/presence/np_c_ffi/src/credentials.rs b/nearby/presence/np_c_ffi/src/credentials.rs index 7dc8ac7..d03f0f6 100644 --- a/nearby/presence/np_c_ffi/src/credentials.rs +++ b/nearby/presence/np_c_ffi/src/credentials.rs
@@ -13,12 +13,16 @@ // limitations under the License. //! Credential-related data-types and functions -use crate::{unwrap, PanicReason}; +use crate::{panic, unwrap, PanicReason}; use core::slice; use np_ffi_core::common::*; -use np_ffi_core::credentials::CredentialBook; -use np_ffi_core::credentials::CredentialSlab; -use np_ffi_core::credentials::*; +use np_ffi_core::credentials::{ + create_credential_book_from_slab, create_credential_slab, deallocate_credential_book, + deallocate_credential_slab, AddV0CredentialToSlabResult, AddV1CredentialToSlabResult, + CredentialBook, CredentialSlab, MatchedCredential, V0DiscoveryCredential, + V1DiscoveryCredential, +}; +use np_ffi_core::declare_enum_cast; use np_ffi_core::deserialize::DecryptedMetadata; use np_ffi_core::deserialize::{ DecryptMetadataResult, DecryptMetadataResultKind, GetMetadataBufferPartsResult, @@ -32,7 +36,61 @@ pub extern "C" fn np_ffi_create_credential_book_from_slab( slab: CredentialSlab, ) -> CreateCredentialBookResult { - create_credential_book_from_slab(slab) + create_credential_book_from_slab(slab).into() +} + +/// Result type for `create_credential_book` +#[repr(u8)] +#[allow(missing_docs)] +pub enum CreateCredentialBookResult { + Success(CredentialBook) = 0, + InvalidSlabHandle = 2, +} + +//TODO: unwrap allocation errors at the ffi-core layer and remove this, after design has been +// agreed upon +impl From<np_ffi_core::credentials::CreateCredentialBookResult> for CreateCredentialBookResult { + fn from(value: np_ffi_core::credentials::CreateCredentialBookResult) -> Self { + match value { + np_ffi_core::credentials::CreateCredentialBookResult::Success(v) => { + CreateCredentialBookResult::Success(v) + } + np_ffi_core::credentials::CreateCredentialBookResult::InvalidSlabHandle => { + CreateCredentialBookResult::InvalidSlabHandle + } + np_ffi_core::credentials::CreateCredentialBookResult::NoSpaceLeft => { + panic(PanicReason::ExceededMaxHandleAllocations) + } + } + } +} + +/// Discriminant for `CreateCredentialBookResult` +#[repr(u8)] +pub enum CreateCredentialBookResultKind { + /// We created a new credential book behind the given handle. + /// The associated payload may be obtained via + /// `CreateCredentialBookResult#into_success()`. + Success = 0, + /// The slab that we tried to create a credential-book from + /// actually was an invalid handle. + InvalidSlabHandle = 1, +} + +impl np_ffi_core::utils::FfiEnum for CreateCredentialBookResult { + type Kind = CreateCredentialBookResultKind; + fn kind(&self) -> Self::Kind { + match self { + CreateCredentialBookResult::Success(_) => CreateCredentialBookResultKind::Success, + CreateCredentialBookResult::InvalidSlabHandle => { + CreateCredentialBookResultKind::InvalidSlabHandle + } + } + } +} + +impl CreateCredentialBookResult { + declare_enum_cast! {into_success, Success, CredentialBook} } /// Gets the tag of a `CreateCredentialBookResult` tagged enum. @@ -70,25 +128,8 @@ /// Allocates a new credential-slab, returning a handle to the created object #[no_mangle] -pub extern "C" fn np_ffi_create_credential_slab() -> CreateCredentialSlabResult { - create_credential_slab() -} - -/// Gets the tag of a `CreateCredentialSlabResult` tagged enum. -#[no_mangle] -pub extern "C" fn np_ffi_CreateCredentialSlabResult_kind( - result: CreateCredentialSlabResult, -) -> CreateCredentialSlabResultKind { - result.kind() -} - -/// Casts a `CreateCredentialSlabResult` to the `SUCCESS` variant, panicking in the -/// case where the passed value is of a different enum variant. -#[no_mangle] -pub extern "C" fn np_ffi_CreateCredentialSlabResult_into_SUCCESS( - result: CreateCredentialSlabResult, -) -> CredentialSlab { - unwrap(result.into_success(), PanicReason::EnumCastFailed) +pub extern "C" fn np_ffi_create_credential_slab() -> CredentialSlab { + unwrap(create_credential_slab().into_success(), PanicReason::ExceededMaxHandleAllocations) } /// Representation of a V0 credential that contains additional data to provide back to caller once it
diff --git a/nearby/presence/np_c_ffi/src/deserialize/v0.rs b/nearby/presence/np_c_ffi/src/deserialize/v0.rs index be68720..243f3ff 100644 --- a/nearby/presence/np_c_ffi/src/deserialize/v0.rs +++ b/nearby/presence/np_c_ffi/src/deserialize/v0.rs
@@ -14,7 +14,6 @@ use crate::{unwrap, PanicReason}; use np_ffi_core::common::DeallocateResult; -use np_ffi_core::deserialize::v0::V0Payload; use np_ffi_core::deserialize::v0::*; use np_ffi_core::deserialize::DecryptMetadataResult; use np_ffi_core::utils::FfiEnum;
diff --git a/nearby/presence/np_c_ffi/src/lib.rs b/nearby/presence/np_c_ffi/src/lib.rs index 2572887..5111aff 100644 --- a/nearby/presence/np_c_ffi/src/lib.rs +++ b/nearby/presence/np_c_ffi/src/lib.rs
@@ -20,9 +20,9 @@ pub mod v0; pub mod v1; -use lock_adapter::std::RwLock; +use lock_adapter::stdlib::RwLock; use lock_adapter::RwLock as _; -use np_ffi_core::common::InvalidStackDataStructure; +use np_ffi_core::common::{CurrentHandleAllocations, InvalidStackDataStructure}; /// Structure for categorized reasons for why a NP C FFI call may /// be panicking. @@ -47,6 +47,10 @@ /// be messing with stack-allocated data structures for this library /// in an entirely unexpected way. InvalidStackDataStructure = 2, + /// The maximum amount of allocations per type is `u32::MAX`, this panic handler is invoked + /// with this reason when this is exceeded. Clients should never need more than 4 Billions + /// handles and would certainly run into other issues before reaching that point + ExceededMaxHandleAllocations = 3, } /// Structure which maintains information about the panic-handler @@ -141,6 +145,13 @@ panic_handler.set_handler(handler) } +/// Checks the current count of all outstanding handle allocations, useful for debugging, +/// logging, and testing +#[no_mangle] +pub extern "C" fn np_ffi_global_config_get_current_allocation_count() -> CurrentHandleAllocations { + np_ffi_core::common::global_config_get_current_allocation_count() +} + /// Sets an override to the number of shards to employ in the NP FFI's /// internal handle-maps, which places an upper bound on the number /// of writing threads which may make progress at any one time @@ -159,125 +170,3 @@ pub extern "C" fn np_ffi_global_config_set_num_shards(num_shards: u8) { np_ffi_core::common::global_config_set_num_shards(num_shards) } - -/// Sets the maximum number of active handles to credential slabs -/// which may be active at any one time. -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Useful for bounding the maximum memory used by the client application -/// on credential slabs in constrained-memory environments. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential slabs. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_credential_slabs(max_num_credential_slabs: u32) { - np_ffi_core::common::global_config_set_max_num_credential_slabs(max_num_credential_slabs) -} - -/// Sets the maximum number of active handles to credential books -/// which may be active at any one time. -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Useful for bounding the maximum memory used by the client application -/// on credential books in constrained-memory environments. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential books. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_credential_books(max_num_credential_books: u32) { - np_ffi_core::common::global_config_set_max_num_credential_books(max_num_credential_books) -} - -/// Sets the maximum number of active handles to deserialized v0 -/// advertisements which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v0 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V0 advertisement. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_deserialized_v0_advertisements( - max_num_deserialized_v0_advertisements: u32, -) { - np_ffi_core::common::global_config_set_max_num_deserialized_v0_advertisements( - max_num_deserialized_v0_advertisements, - ) -} - -/// Sets the maximum number of active handles to deserialized v1 -/// advertisements which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v1 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V1 advertisement. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_deserialized_v1_advertisements( - max_num_deserialized_v1_advertisements: u32, -) { - np_ffi_core::common::global_config_set_max_num_deserialized_v1_advertisements( - max_num_deserialized_v1_advertisements, - ) -} - -/// Sets the maximum number of active handles to v0 advertisement -/// builders which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v0 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a V0 advertisement builder. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_v0_advertisement_builders( - max_num_v0_advertisement_builders: u32, -) { - np_ffi_core::common::global_config_set_max_num_v0_advertisement_builders( - max_num_v0_advertisement_builders, - ) -} - -/// Sets the maximum number of active handles to v1 advertisement -/// builders which may be active at any one time. -/// -/// Useful for bounding the maximum memory used by the client application -/// on v1 advertisements in constrained-memory environments. -/// -/// Default value: Max value. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a V1 advertisement builder. -#[no_mangle] -pub extern "C" fn np_ffi_global_config_set_max_num_v1_advertisement_builders( - max_num_v1_advertisement_builders: u32, -) { - np_ffi_core::common::global_config_set_max_num_v1_advertisement_builders( - max_num_v1_advertisement_builders, - ) -}
diff --git a/nearby/presence/np_c_ffi/src/serialize/v0.rs b/nearby/presence/np_c_ffi/src/serialize/v0.rs index 962522e..867c33b 100644 --- a/nearby/presence/np_c_ffi/src/serialize/v0.rs +++ b/nearby/presence/np_c_ffi/src/serialize/v0.rs
@@ -15,7 +15,7 @@ //! NP Rust C FFI functionality for V0 advertisement serialization. use crate::{panic_if_invalid, unwrap, PanicReason}; -use np_ffi_core::common::{ByteBuffer, DeallocateResult, EncryptedIdentityType, FixedSizeArray}; +use np_ffi_core::common::{ByteBuffer, DeallocateResult, FixedSizeArray}; use np_ffi_core::credentials::V0BroadcastCredential; use np_ffi_core::serialize::v0::*; use np_ffi_core::utils::FfiEnum; @@ -55,38 +55,25 @@ adv_builder.deallocate() } -/// Gets the tag of a `CreateV0AdvertisementBuilderResult` tagged-union. -#[no_mangle] -pub extern "C" fn np_ffi_CreateV0AdvertisementBuilderResult_kind( - result: CreateV0AdvertisementBuilderResult, -) -> CreateV0AdvertisementBuilderResultKind { - result.kind() -} - -/// Casts a `CreateV0AdvertisementBuilderResult` to the `Success` variant, -/// panicking in the case where the passed value is of a different enum variant. -#[no_mangle] -pub extern "C" fn np_ffi_CreateV0AdvertisementBuilderResult_into_SUCCESS( - result: CreateV0AdvertisementBuilderResult, -) -> V0AdvertisementBuilder { - unwrap(result.into_success(), PanicReason::EnumCastFailed) -} - /// Creates a new V0 advertisement builder for a public advertisement. #[no_mangle] -pub extern "C" fn np_ffi_create_v0_public_advertisement_builder( -) -> CreateV0AdvertisementBuilderResult { - create_v0_public_advertisement_builder() +pub extern "C" fn np_ffi_create_v0_public_advertisement_builder() -> V0AdvertisementBuilder { + unwrap( + create_v0_public_advertisement_builder().into_success(), + PanicReason::ExceededMaxHandleAllocations, + ) } /// Creates a new V0 advertisement builder for an encrypted advertisement. #[no_mangle] pub extern "C" fn np_ffi_create_v0_encrypted_advertisement_builder( broadcast_cred: V0BroadcastCredential, - identity_type: EncryptedIdentityType, salt: FixedSizeArray<2>, -) -> CreateV0AdvertisementBuilderResult { - create_v0_encrypted_advertisement_builder(broadcast_cred, identity_type, salt) +) -> V0AdvertisementBuilder { + unwrap( + create_v0_encrypted_advertisement_builder(broadcast_cred, salt).into_success(), + PanicReason::ExceededMaxHandleAllocations, + ) } /// Gets the tag of a `SerializeV0AdvertisementResult` tagged-union.
diff --git a/nearby/presence/np_c_ffi/src/serialize/v1.rs b/nearby/presence/np_c_ffi/src/serialize/v1.rs index c8ba135..484425b 100644 --- a/nearby/presence/np_c_ffi/src/serialize/v1.rs +++ b/nearby/presence/np_c_ffi/src/serialize/v1.rs
@@ -15,7 +15,7 @@ //! NP Rust C FFI functionality for V1 advertisement serialization. use crate::{unwrap, PanicReason}; -use np_ffi_core::common::{ByteBuffer, EncryptedIdentityType, FixedSizeArray}; +use np_ffi_core::common::{ByteBuffer, FixedSizeArray}; use np_ffi_core::credentials::V1BroadcastCredential; use np_ffi_core::serialize::v1::*; use np_ffi_core::serialize::AdvertisementBuilderKind; @@ -56,10 +56,9 @@ pub extern "C" fn np_ffi_V1AdvertisementBuilder_encrypted_section_builder( adv_builder: V1AdvertisementBuilder, broadcast_cred: V1BroadcastCredential, - identity_type: EncryptedIdentityType, verification_mode: V1VerificationMode, ) -> CreateV1SectionBuilderResult { - adv_builder.encrypted_section_builder(broadcast_cred, identity_type, verification_mode) + adv_builder.encrypted_section_builder(broadcast_cred, verification_mode) } /// Attempts to serialize the contents of the advertisement builder @@ -73,30 +72,16 @@ adv_builder.into_advertisement() } -/// Gets the tag of a `CreateV1AdvertisementBuilderResult` tagged-union. -#[no_mangle] -pub extern "C" fn np_ffi_CreateV1AdvertisementBuilderResult_kind( - result: CreateV1AdvertisementBuilderResult, -) -> CreateV1AdvertisementBuilderResultKind { - result.kind() -} - -/// Casts a `CreateV1AdvertisementBuilderResult` to the `Success` variant, -/// panicking in the case where the passed value is of a different enum variant. -#[no_mangle] -pub extern "C" fn np_ffi_CreateV1AdvertisementBuilderResult_into_SUCCESS( - result: CreateV1AdvertisementBuilderResult, -) -> V1AdvertisementBuilder { - unwrap(result.into_success(), PanicReason::EnumCastFailed) -} - /// Creates a new V1 advertisement builder for the given advertisement /// kind (public/encrypted). #[no_mangle] pub extern "C" fn np_ffi_create_v1_advertisement_builder( kind: AdvertisementBuilderKind, -) -> CreateV1AdvertisementBuilderResult { - create_v1_advertisement_builder(kind) +) -> V1AdvertisementBuilder { + unwrap( + create_v1_advertisement_builder(kind).into_success(), + PanicReason::ExceededMaxHandleAllocations, + ) } /// Gets the tag of a `SerializeV1AdvertisementResult` tagged-union.
diff --git a/nearby/presence/np_c_ffi/src/v0.rs b/nearby/presence/np_c_ffi/src/v0.rs index 17302aa..7bcb980 100644 --- a/nearby/presence/np_c_ffi/src/v0.rs +++ b/nearby/presence/np_c_ffi/src/v0.rs
@@ -110,27 +110,13 @@ /// Return whether a boolean action type is set in this data element #[no_mangle] -pub extern "C" fn np_ffi_V0Actions_has_action( - actions: V0Actions, - action_type: BooleanActionType, -) -> bool { +pub extern "C" fn np_ffi_V0Actions_has_action(actions: V0Actions, action_type: ActionType) -> bool { match actions.has_action(action_type) { Ok(b) => b, Err(_) => panic(PanicReason::InvalidStackDataStructure), } } -/// Gets the 4 bit context sync sequence number as a u8 from this data element -#[no_mangle] -pub extern "C" fn np_ffi_V0Actions_get_context_sync_sequence_number( - actions: V0Actions, -) -> ContextSyncSeqNum { - match actions.get_context_sync_seq_num() { - Ok(b) => b, - Err(_) => panic(PanicReason::InvalidStackDataStructure), - } -} - /// Attempts to set the given action bit to the given boolean value. /// This operation may fail if the requested action bit may not be /// set for the kind of containing advertisement (public/encrypted) @@ -140,56 +126,15 @@ #[no_mangle] pub extern "C" fn np_ffi_V0Actions_set_action( actions: V0Actions, - action_type: BooleanActionType, + action_type: ActionType, value: bool, ) -> SetV0ActionResult { panic_if_invalid(actions.set_action(action_type, value)) } -/// Sets the context sequence number for the given Actions DE. -#[no_mangle] -pub extern "C" fn np_ffi_V0Actions_set_context_sync_sequence_number( - actions: V0Actions, - value: ContextSyncSeqNum, -) -> V0Actions { - panic_if_invalid(actions.set_context_sync_seq_num(value)) -} - /// Returns the representation of the passed `V0Actions` as an unsigned /// integer, where the bit-positions correspond to individual actions. #[no_mangle] pub extern "C" fn np_ffi_V0Actions_as_u32(actions: V0Actions) -> u32 { actions.as_u32() } - -/// Gets the tag of a `BuildContextSyncSeqNumResult` tagged-union. -#[no_mangle] -pub extern "C" fn np_ffi_BuildContextSyncSeqNumResult_kind( - result: BuildContextSyncSeqNumResult, -) -> BuildContextSyncSeqNumResultKind { - result.kind() -} - -/// Casts a `BuildContextSyncSeqNumResult` to the `Success` variant, panicking in the -/// case where the passed value is of a different enum variant. -#[no_mangle] -pub extern "C" fn np_ffi_BuildContextSyncSeqNumResult_into_SUCCESS( - result: BuildContextSyncSeqNumResult, -) -> ContextSyncSeqNum { - unwrap(result.into_success(), PanicReason::EnumCastFailed) -} - -/// Attempts to build a new context sync sequence number -/// from the given unsigned byte. -#[no_mangle] -pub extern "C" fn np_ffi_ContextSyncSeqNum_build_from_unsigned_byte( - value: u8, -) -> BuildContextSyncSeqNumResult { - ContextSyncSeqNum::build_from_unsigned_byte(value) -} - -/// Gets the value of the given context-sync sequence number as an unsigned byte. -#[no_mangle] -pub extern "C" fn np_ffi_ContextSyncSeqNum_as_unsigned_byte(seq_num: ContextSyncSeqNum) -> u8 { - seq_num.as_u8() -}
diff --git a/nearby/presence/np_cpp_ffi/benchmarks/np_c_ffi_benches.cc b/nearby/presence/np_cpp_ffi/benchmarks/np_c_ffi_benches.cc index 02bd4ca..1822741 100644 --- a/nearby/presence/np_cpp_ffi/benchmarks/np_c_ffi_benches.cc +++ b/nearby/presence/np_cpp_ffi/benchmarks/np_c_ffi_benches.cc
@@ -24,13 +24,7 @@ void V0PlaintextCApi(benchmark::State &state) { auto num_ciphers = state.range(0); - auto slab_result = np_ffi::internal::np_ffi_create_credential_slab(); - assert( - np_ffi::internal::np_ffi_CreateCredentialSlabResult_kind(slab_result) == - np_ffi::internal::CreateCredentialSlabResultKind::Success); - auto slab = np_ffi::internal::np_ffi_CreateCredentialSlabResult_into_SUCCESS( - slab_result); - + auto slab = np_ffi::internal::np_ffi_create_credential_slab(); auto book_result = np_ffi::internal::np_ffi_create_credential_book_from_slab(slab); assert(
diff --git a/nearby/presence/np_cpp_ffi/benchmarks/np_cpp_benches.cc b/nearby/presence/np_cpp_ffi/benchmarks/np_cpp_benches.cc index 2a3b010..392d679 100644 --- a/nearby/presence/np_cpp_ffi/benchmarks/np_cpp_benches.cc +++ b/nearby/presence/np_cpp_ffi/benchmarks/np_cpp_benches.cc
@@ -16,18 +16,14 @@ #include "shared_test_util.h" // needed for running directly against the C API (ie: bypassing the C++ wrapper) +#include "benchmark/benchmark.h" #include "np_cpp_ffi_functions.h" #include "np_cpp_ffi_types.h" -#include "benchmark/benchmark.h" - nearby_protocol::CredentialBook CreateEmptyCredBook() { - auto cred_slab = nearby_protocol::CredentialSlab::TryCreate(); - assert(cred_slab.ok()); - auto cred_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(cred_slab.value()); - assert(cred_book.ok()); - return std::move(*cred_book); + nearby_protocol::CredentialSlab cred_slab; + nearby_protocol::CredentialBook cred_book(cred_slab); + return std::move(cred_book); } void V0Plaintext(benchmark::State &state) { @@ -65,19 +61,16 @@ ->Unit(benchmark::kMicrosecond); class V0Encrypted : public benchmark::Fixture { -public: + public: std::optional<nearby_protocol::CredentialBook> cred_book_; void SetUp(const ::benchmark::State &state) override { // populate credential book auto num_creds = state.range(0); - auto slab = nearby_protocol::CredentialSlab::TryCreate(); - assert(slab.ok()); - + nearby_protocol::CredentialSlab slab; for (int i = 1; i < num_creds; i++) { auto credential = GenerateRandomCredentialV0(); - auto result = slab->AddV0Credential(credential); - assert(result.ok()); + slab.AddV0Credential(credential); } // now at the end of the list add the matching credential @@ -86,13 +79,11 @@ std::array<uint8_t, 32> key_seed = {}; std::fill_n(key_seed.begin(), 32, 0x11); nearby_protocol::V0MatchableCredential v0_cred( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data); - auto add_result = slab->AddV0Credential(v0_cred); - assert(add_result.ok()); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data); + slab.AddV0Credential(v0_cred); - auto cred_book = nearby_protocol::CredentialBook::TryCreateFromSlab(*slab); - assert(cred_book.ok()); - cred_book_ = std::move(*cred_book); + nearby_protocol::CredentialBook cred_book(slab); + cred_book_ = std::move(cred_book); } void TearDown(const ::benchmark::State &state) override {} }; @@ -119,29 +110,27 @@ ->Unit(benchmark::kMicrosecond); class V1SigEncryptedSingleSection : public benchmark::Fixture { -public: + public: std::optional<nearby_protocol::CredentialBook> cred_book_; void SetUp(const ::benchmark::State &state) override { // populate credential book auto num_creds = state.range(0); - auto slab = nearby_protocol::CredentialSlab::TryCreate(); - assert(slab.ok()); + nearby_protocol::CredentialSlab slab; for (int i = 1; i < num_creds; i++) { auto credential = GenerateRandomCredentialV1(); - auto result = slab->AddV1Credential(credential); + auto result = slab.AddV1Credential(credential); assert(result.ok()); } // now at the end of the list add the matching credential nearby_protocol::MatchedCredentialData match_data(123, V1AdvEncryptedMetadata); nearby_protocol::V1MatchableCredential v1_cred( - V1AdvKeySeed, V1AdvExpectedUnsignedMetadataKeyHmac, - V1AdvExpectedSignedMetadataKeyHmac, V1AdvPublicKey, match_data); - auto add_result = slab->AddV1Credential(v1_cred); + V1AdvKeySeed, V1AdvExpectedMicExtendedSaltIdentityTokenHmac, + V1AdvExpectedSignatureIdentityTokenHmac, V1AdvPublicKey, match_data); + auto add_result = slab.AddV1Credential(v1_cred); assert(add_result.ok()); - auto cred_book = nearby_protocol::CredentialBook::TryCreateFromSlab(*slab); - assert(cred_book.ok()); - cred_book_ = std::move(*cred_book); + nearby_protocol::CredentialBook cred_book(slab); + cred_book_ = std::move(cred_book); } void TearDown(const ::benchmark::State &state) override {} }; @@ -187,7 +176,7 @@ } class LoadCredentialBook : public benchmark::Fixture { -public: + public: std::vector<V1CredentialData> creds_; // generate all the data in setup so the time for generation is not included // in the measurement @@ -204,19 +193,17 @@ BENCHMARK_DEFINE_F(LoadCredentialBook, SingleMatchingCredential) (benchmark::State &state) { for ([[maybe_unused]] auto _ : state) { - auto slab = nearby_protocol::CredentialSlab::TryCreate(); - assert(slab.ok()); + nearby_protocol::CredentialSlab slab; for (auto cred : creds_) { nearby_protocol::MatchedCredentialData m(cred.cred_id, cred.encrypted_metadata_bytes); nearby_protocol::V1MatchableCredential v1_cred( cred.key_seed, cred.expected_unsigned_metadata_key_hmac, cred.expected_signed_metadata_key_hmac, cred.pub_key, m); - auto result = slab->AddV1Credential(v1_cred); + auto result = slab.AddV1Credential(v1_cred); assert(result.ok()); } - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(*slab); - assert(book.ok()); + nearby_protocol::CredentialBook book(slab); benchmark::DoNotOptimize(book); } }
diff --git a/nearby/presence/np_cpp_ffi/fuzz/deserialization_fuzzer.cc b/nearby/presence/np_cpp_ffi/fuzz/deserialization_fuzzer.cc index d18b83e..7108e0a 100644 --- a/nearby/presence/np_cpp_ffi/fuzz/deserialization_fuzzer.cc +++ b/nearby/presence/np_cpp_ffi/fuzz/deserialization_fuzzer.cc
@@ -47,17 +47,15 @@ void HandleAdvertisementResult(nearby_protocol::DeserializeAdvertisementResult); void PlaintextDeserializer(std::span<const uint8_t> adv_bytes) { - auto slab = nearby_protocol::CredentialSlab::TryCreate(); - EXPECT_TRUE(slab.ok()); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(*slab); - EXPECT_TRUE(book.ok()); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto buffer = nearby_protocol::ByteBuffer<255>::TryFromSpan(adv_bytes); EXPECT_TRUE(buffer.ok()); nearby_protocol::RawAdvertisementPayload payload( (nearby_protocol::ByteBuffer<255>(*buffer))); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement(payload, *book); + nearby_protocol::Deserializer::DeserializeAdvertisement(payload, book); // Since we are seeding with valid data, we can add extra calls into the // result processing APIs to ensure none of the internal asserts are @@ -78,22 +76,24 @@ uint32_t credential_id; std::array<uint8_t, 32> key_seed; std::array<uint8_t, 32> legacy_metadata_key_hmac; - std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac; - std::array<uint8_t, 32> expected_signed_metadata_key_hmac; + std::array<uint8_t, 32> expected_unsigned_identity_token_hmac; + std::array<uint8_t, 32> expected_signed_identity_token_hmac; std::array<uint8_t, 32> pub_key; std::vector<uint8_t> encrypted_metadata_bytes; }; static struct IdentityData V0TestCaseIdentityData { .credential_id = static_cast<uint32_t>(rand()), .key_seed = V0AdvKeySeed, - .legacy_metadata_key_hmac = V0AdvLegacyMetadataKeyHmac, + .legacy_metadata_key_hmac = V0AdvLegacyIdentityTokenHmac, .encrypted_metadata_bytes = V0AdvEncryptedMetadata }; static struct IdentityData V1TestCaseIdentityData { .credential_id = static_cast<uint32_t>(rand()), .key_seed = V1AdvKeySeed, - .expected_unsigned_metadata_key_hmac = V1AdvExpectedUnsignedMetadataKeyHmac, - .expected_signed_metadata_key_hmac = V1AdvExpectedSignedMetadataKeyHmac, + .expected_unsigned_identity_token_hmac = + V1AdvExpectedMicExtendedSaltIdentityTokenHmac, + .expected_signed_identity_token_hmac = + V1AdvExpectedSignatureIdentityTokenHmac, .pub_key = V1AdvPublicKey, .encrypted_metadata_bytes = V1AdvEncryptedMetadata, }; @@ -105,9 +105,7 @@ // and combinations of matching and undecryptable sections etc. void DeserializeWithCredentials(std::span<const IdentityData> identities, std::span<const uint8_t> adv_bytes) { - auto slab = nearby_protocol::CredentialSlab::TryCreate(); - EXPECT_TRUE(slab.ok()); - + nearby_protocol::CredentialSlab slab; // populate book with fuzzer generated credential data for (auto data : identities) { nearby_protocol::MatchedCredentialData match_data( @@ -115,23 +113,22 @@ nearby_protocol::V0MatchableCredential v0_cred( data.key_seed, data.legacy_metadata_key_hmac, match_data); // adding v0 credentials is infallible - EXPECT_TRUE(slab->AddV0Credential(v0_cred).ok()); + slab.AddV0Credential(v0_cred); nearby_protocol::V1MatchableCredential v1_cred( - data.key_seed, data.expected_unsigned_metadata_key_hmac, - data.expected_signed_metadata_key_hmac, data.pub_key, match_data); - [[maybe_unused]] auto result = slab->AddV1Credential(v1_cred); + data.key_seed, data.expected_unsigned_identity_token_hmac, + data.expected_signed_identity_token_hmac, data.pub_key, match_data); + [[maybe_unused]] auto result = slab.AddV1Credential(v1_cred); } - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(*slab); - EXPECT_TRUE(book.ok()); + nearby_protocol::CredentialBook book(slab); auto buffer = nearby_protocol::ByteBuffer<255>::TryFromSpan(adv_bytes); EXPECT_TRUE(buffer.ok()); nearby_protocol::RawAdvertisementPayload payload( (nearby_protocol::ByteBuffer<255>(*buffer))); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement(payload, *book); + nearby_protocol::Deserializer::DeserializeAdvertisement(payload, book); // Since we are seeding with valid data, we can add extra calls into the // result processing APIs to ensure none of the internal asserts are
diff --git a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h index 1cc73d7..5e064f9 100644 --- a/nearby/presence/np_cpp_ffi/include/nearby_protocol.h +++ b/nearby/presence/np_cpp_ffi/include/nearby_protocol.h
@@ -61,22 +61,20 @@ namespace nearby_protocol { // Re-exporting cbindgen generated types which are used in the public API +using np_ffi::internal::ActionType; using np_ffi::internal::AddV0CredentialToSlabResult; using np_ffi::internal::AddV0DEResult; using np_ffi::internal::AddV1CredentialToSlabResult; using np_ffi::internal::AdvertisementBuilderKind; -using np_ffi::internal::BooleanActionType; using np_ffi::internal::CreateCredentialBookResultKind; -using np_ffi::internal::CreateCredentialSlabResultKind; -using np_ffi::internal::CreateV0AdvertisementBuilderResultKind; using np_ffi::internal::CreateV1SectionBuilderResultKind; +using np_ffi::internal::CurrentHandleAllocations; using np_ffi::internal::DeserializeAdvertisementResultKind; using np_ffi::internal::DeserializedV0AdvertisementKind; using np_ffi::internal::DeserializedV0IdentityDetails; using np_ffi::internal::DeserializedV0IdentityKind; using np_ffi::internal::DeserializedV1IdentityDetails; using np_ffi::internal::DeserializedV1IdentityKind; -using np_ffi::internal::EncryptedIdentityType; using np_ffi::internal::GetV0DEResultKind; using np_ffi::internal::PanicReason; using np_ffi::internal::SerializeV0AdvertisementResultKind; @@ -140,43 +138,17 @@ // np_ffi_global_config_set_num_shards in np_cpp_ffi_functions.h for more info static void SetNumShards(uint8_t num_shards); - // Sets the maximum number of active handles to credential slabs which may be - // active at any one time. See - // np_ffi_global_config_set_max_num_credential_slabs in np_cpp_ffi_functions.h - // for more info - static void SetMaxNumCredentialSlabs(uint32_t max_num_credential_slabs); - - // Sets the maximum number of active handles to credential books which may be - // active at any one time. See - // np_ffi_global_config_set_max_num_credential_books in np_cpp_ffi_functions.h - // for more info - static void SetMaxNumCredentialBooks(uint32_t max_num_credential_books); - - // Sets the maximum number of active handles to deserialized v0 advertisements - // which may be active at any one time. See - // np_ffi_global_config_set_max_num_deserialized_v0_advertisements for more - // info. - static void SetMaxNumDeserializedV0Advertisements( - uint32_t max_num_deserialized_v0_advertisements); - - // Sets the maximum number of active handles to deserialized v1 advertisements - // which may be active at any one time - static void SetMaxNumDeserializedV1Advertisements( - uint32_t max_num_deserialized_v1_advertisements); - - // Sets the maximum number of active handles to v0 advertisement builders - // which may be active at any one time - static void SetMaxNumV0AdvertisementBuilders( - uint32_t max_num_v0_advertisement_builders); + // Checks the current count of all outstanding handle allocations, useful for + // debugging, logging, and testing + static CurrentHandleAllocations GetCurrentHandleAllocationCount(); }; // Holds the credentials used in the construction of a credential book // using CredentialBook::TryCreateFromSlab() class CredentialSlab { public: - // Don't allow copy constructor, copy-assignment or default constructor, since + // Don't allow copy constructor or copy-assignment since // this class wraps a handle to externally allocated resources. - CredentialSlab() = delete; CredentialSlab(const CredentialSlab &other) = delete; CredentialSlab &operator=(const CredentialSlab &other) = delete; @@ -185,26 +157,23 @@ CredentialSlab(CredentialSlab &&other) noexcept; CredentialSlab &operator=(CredentialSlab &&other) noexcept; + // Creates a new instance of a CredentialSlab, returns the CredentialSlab on + // success or a Status code on failure + CredentialSlab(); + // The destructor for a CredentialSlab, this will be called when a // CredentialSlab instance goes out of scope and will free the underlying // resources ~CredentialSlab(); - // Creates a new instance of a CredentialSlab, returns the CredentialSlab on - // success or a Status code on failure - [[nodiscard]] static absl::StatusOr<CredentialSlab> TryCreate(); - // Adds a V0 credential to the slab - [[nodiscard]] absl::Status AddV0Credential(V0MatchableCredential v0_cred); + void AddV0Credential(V0MatchableCredential v0_cred); // Adds a V1 credential to the slab [[nodiscard]] absl::Status AddV1Credential(V1MatchableCredential v1_cred); private: friend class CredentialBook; - explicit CredentialSlab(np_ffi::internal::CredentialSlab credential_slab) - : credential_slab_(credential_slab), moved_(false) {} - np_ffi::internal::CredentialSlab credential_slab_; bool moved_; }; @@ -234,14 +203,10 @@ // returning the CredentialBook on success or a Status code on failure. // The passed credential-slab will be deallocated if this operation // is successful. - [[nodiscard]] static absl::StatusOr<CredentialBook> TryCreateFromSlab( - CredentialSlab &slab); + CredentialBook(CredentialSlab &slab); private: friend class Deserializer; - explicit CredentialBook(np_ffi::internal::CredentialBook credential_book) - : credential_book_(credential_book), moved_(false) {} - np_ffi::internal::CredentialBook credential_book_; bool moved_; }; @@ -311,9 +276,9 @@ V0BroadcastCredential() = delete; // Creates a new V0Broadcast credential with the given - // key seed and metadata key. + // key seed and identity token. [[nodiscard]] V0BroadcastCredential(std::array<uint8_t, 32> key_seed, - std::array<uint8_t, 14> metadata_key); + std::array<uint8_t, 14> identity_token); private: friend class V0AdvertisementBuilder; @@ -578,12 +543,12 @@ // Decrypts the metadata of the credential which matched with this // advertisement, or returns an error if the metadata key is invalid and // unable to successfully decrypt the metadata. - [[nodiscard]] absl::StatusOr<std::vector<uint8_t>> DecryptMetadata() const; + [[nodiscard]] absl::StatusOr<std::vector<uint8_t>> TryDecryptMetadata() const; // Gets the details of the identity data element of this payload or returns an // error if the payload does not have an identity (public advertisement) [[nodiscard]] absl::StatusOr<DeserializedV0IdentityDetails> - GetIdentityDetails() const; + TryGetIdentityDetails() const; private: friend class LegibleDeserializedV0Advertisement; @@ -638,28 +603,6 @@ np_ffi::internal::V0DataElement v0_data_element_; }; -// A Context Sync Sequence Number [0-15] -class ContextSyncSeqNum { - public: - ContextSyncSeqNum() = delete; - - // Gets the value of this context-sync sequence number. - [[nodiscard]] uint8_t GetAsU8() const; - - // Attempts to construct a context-sync sequence number with the given - // value contained in an unsigned byte. If the number may not be - // represented in a single nibble, this method will return an - // invalid argument error. - [[nodiscard]] static absl::StatusOr<ContextSyncSeqNum> TryBuildFromU8( - uint8_t value); - - private: - friend class V0Actions; - explicit ContextSyncSeqNum(np_ffi::internal::ContextSyncSeqNum seq_num) - : seq_num_(seq_num) {} - np_ffi::internal::ContextSyncSeqNum seq_num_; -}; - // A V0 Actions Data Element class V0Actions { public: @@ -670,20 +613,14 @@ [[nodiscard]] uint32_t GetAsU32() const; /// Return whether a boolean action type is present in this data element - [[nodiscard]] bool HasAction(BooleanActionType action) const; - - /// Gets the 4 bit context sync sequence number from this data element - [[nodiscard]] ContextSyncSeqNum GetContextSyncSequenceNumber() const; + [[nodiscard]] bool HasAction(ActionType action) const; /// Attempts to set the given action bit to the given boolean value. /// This operation may fail with an invalid argument error /// if the requested action bit may not be set given the encoding /// of the containing advertisement. /// In this case, the action bits will be unaltered by this call. - absl::Status TrySetAction(BooleanActionType action, bool value); - - /// Sets the context sync sequence number. - void SetContextSyncSequenceNumber(ContextSyncSeqNum seq_num); + absl::Status TrySetAction(ActionType action, bool value); // Constructs an all-zeroed V0 actions DE for the given advertisement builder // kind. @@ -746,7 +683,8 @@ uint8_t index) const; // Decrypts the metadata of the credential which matched with this section - [[nodiscard]] absl::StatusOr<std::vector<uint8_t>> DecryptMetadata() const; + // or returns an error in the case that the metadata could not be decrypted + [[nodiscard]] absl::StatusOr<std::vector<uint8_t>> TryDecryptMetadata() const; // Gets the details of the identity data element of this section or returns an // error if the section does not contain an identity (public section) @@ -829,20 +767,14 @@ // Creates a new V0 advertisement builder for a public advertisement, // or returns a Status code on failure. - [[nodiscard]] static absl::StatusOr<V0AdvertisementBuilder> TryCreatePublic(); + [[nodiscard]] static V0AdvertisementBuilder CreatePublic(); // Creates a new V0 advertisement builder for an encrypted advertisement, // or returns a Status code on failure. - [[nodiscard]] static absl::StatusOr<V0AdvertisementBuilder> - TryCreateEncrypted(V0BroadcastCredential broadcast_cred, - EncryptedIdentityType identity_type, - std::array<uint8_t, 2> salt); + [[nodiscard]] static V0AdvertisementBuilder CreateEncrypted( + V0BroadcastCredential broadcast_cred, std::array<uint8_t, 2> salt); private: - [[nodiscard]] static absl::StatusOr<V0AdvertisementBuilder> - CreateV0AdvertisementBuilderResultToInternal( - np_ffi::internal::CreateV0AdvertisementBuilderResult result); - explicit V0AdvertisementBuilder( np_ffi::internal::V0AdvertisementBuilder adv_builder) : adv_builder_(adv_builder), moved_(false) {}
diff --git a/nearby/presence/np_cpp_ffi/nearby_protocol.cc b/nearby/presence/np_cpp_ffi/nearby_protocol.cc index 360f7ad..510844a 100644 --- a/nearby/presence/np_cpp_ffi/nearby_protocol.cc +++ b/nearby/presence/np_cpp_ffi/nearby_protocol.cc
@@ -74,54 +74,13 @@ np_ffi::internal::np_ffi_global_config_set_num_shards(num_shards); } -void GlobalConfig::SetMaxNumCredentialSlabs( - const uint32_t max_num_credential_slabs) { - np_ffi::internal::np_ffi_global_config_set_max_num_credential_slabs( - max_num_credential_slabs); +CurrentHandleAllocations GlobalConfig::GetCurrentHandleAllocationCount() { + return np_ffi::internal::np_ffi_global_config_get_current_allocation_count(); } -void GlobalConfig::SetMaxNumCredentialBooks( - const uint32_t max_num_credential_books) { - np_ffi::internal::np_ffi_global_config_set_max_num_credential_books( - max_num_credential_books); -} - -void GlobalConfig::SetMaxNumDeserializedV0Advertisements( - const uint32_t max_num_deserialized_v0_advertisements) { - np_ffi::internal:: - np_ffi_global_config_set_max_num_deserialized_v0_advertisements( - max_num_deserialized_v0_advertisements); -} - -void GlobalConfig::SetMaxNumDeserializedV1Advertisements( - const uint32_t max_num_deserialized_v1_advertisements) { - np_ffi::internal:: - np_ffi_global_config_set_max_num_deserialized_v1_advertisements( - max_num_deserialized_v1_advertisements); -} - -void GlobalConfig::SetMaxNumV0AdvertisementBuilders( - uint32_t max_num_v0_advertisement_builders) { - np_ffi::internal::np_ffi_global_config_set_max_num_v0_advertisement_builders( - max_num_v0_advertisement_builders); -} - -absl::StatusOr<CredentialSlab> CredentialSlab::TryCreate() { - auto result = np_ffi::internal::np_ffi_create_credential_slab(); - auto kind = np_ffi::internal::np_ffi_CreateCredentialSlabResult_kind(result); - - switch (kind) { - case CreateCredentialSlabResultKind::Success: { - auto slab = CredentialSlab( - np_ffi::internal::np_ffi_CreateCredentialSlabResult_into_SUCCESS( - result)); - return slab; - } - case CreateCredentialSlabResultKind::NoSpaceLeft: { - return absl::ResourceExhaustedError( - "No space left to create credential slab"); - } - } +CredentialSlab::CredentialSlab() { + this->credential_slab_ = np_ffi::internal::np_ffi_create_credential_slab(); + this->moved_ = false; } CredentialSlab::~CredentialSlab() { @@ -155,20 +114,13 @@ return *this; } -absl::Status CredentialSlab::AddV0Credential( - const V0MatchableCredential v0_cred) { +void CredentialSlab::AddV0Credential(const V0MatchableCredential v0_cred) { assert_panic(!this->moved_); auto result = np_ffi::internal::np_ffi_CredentialSlab_add_v0_credential( this->credential_slab_, v0_cred.internal_); - switch (result) { - case AddV0CredentialToSlabResult::Success: { - return absl::OkStatus(); - } - case AddV0CredentialToSlabResult::InvalidHandle: { - return absl::InvalidArgumentError( - "invalid credential slab handle provided"); - } - } + // Add V0 is infallible since the handle is guaranteed to be correct by the + // C++ wrapper + assert_panic(result == AddV0CredentialToSlabResult::Success); } absl::Status CredentialSlab::AddV1Credential( @@ -191,29 +143,17 @@ } } -absl::StatusOr<CredentialBook> CredentialBook::TryCreateFromSlab( - CredentialSlab& slab) { +CredentialBook::CredentialBook(CredentialSlab& slab) { assert_panic(!slab.moved_); auto result = np_ffi::internal::np_ffi_create_credential_book_from_slab( slab.credential_slab_); auto kind = np_ffi::internal::np_ffi_CreateCredentialBookResult_kind(result); - switch (kind) { - case CreateCredentialBookResultKind::Success: { - auto book = - np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS( - result); - slab.moved_ = true; - return CredentialBook(book); - } - case CreateCredentialBookResultKind::NoSpaceLeft: { - return absl::ResourceExhaustedError( - "No space left to create credential book"); - } - case CreateCredentialBookResultKind::InvalidSlabHandle: { - return absl::NotFoundError( - "The slab referenced by the given handle was not found."); - } - } + // Handle is guaranteed to be valid by the C++ wrapper + assert_panic(kind == CreateCredentialBookResultKind::Success); + slab.moved_ = true; + this->credential_book_ = + np_ffi::internal::np_ffi_CreateCredentialBookResult_into_SUCCESS(result); + this->moved_ = false; } CredentialBook::~CredentialBook() { @@ -500,12 +440,13 @@ return result; } case np_ffi::internal::DecryptMetadataResultKind::Error: { - return absl::InvalidArgumentError("Invalid V0 payload handle"); + return absl::InvalidArgumentError( + "Decrypt attempt failed, identity is missing or invalid"); } } } -absl::StatusOr<DeserializedV0IdentityDetails> V0Payload::GetIdentityDetails() +absl::StatusOr<DeserializedV0IdentityDetails> V0Payload::TryGetIdentityDetails() const { assert_panic(!this->moved_); auto result = np_ffi::internal::np_ffi_V0Payload_get_identity_details( @@ -513,7 +454,8 @@ auto kind = np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_kind(result); switch (kind) { case np_ffi::internal::GetV0IdentityDetailsResultKind::Error: { - return absl::InvalidArgumentError("Invalid handle"); + return absl::InvalidArgumentError( + "Identity details not available for public advertisements"); } case np_ffi::internal::GetV0IdentityDetailsResultKind::Success: { return np_ffi::internal::np_ffi_GetV0IdentityDetailsResult_into_SUCCESS( @@ -522,7 +464,7 @@ } } -absl::StatusOr<std::vector<uint8_t>> V0Payload::DecryptMetadata() const { +absl::StatusOr<std::vector<uint8_t>> V0Payload::TryDecryptMetadata() const { assert_panic(!this->moved_); auto decrypt_result = np_ffi::internal::np_ffi_V0Payload_decrypt_metadata(this->v0_payload_); @@ -558,17 +500,11 @@ return np_ffi::internal::np_ffi_V0Actions_as_u32(actions_); } -bool V0Actions::HasAction(BooleanActionType action) const { +bool V0Actions::HasAction(ActionType action) const { return np_ffi::internal::np_ffi_V0Actions_has_action(actions_, action); } -ContextSyncSeqNum V0Actions::GetContextSyncSequenceNumber() const { - return ContextSyncSeqNum( - np_ffi::internal::np_ffi_V0Actions_get_context_sync_sequence_number( - actions_)); -} - -absl::Status V0Actions::TrySetAction(BooleanActionType action, bool value) { +absl::Status V0Actions::TrySetAction(ActionType action, bool value) { auto result = np_ffi::internal::np_ffi_V0Actions_set_action(actions_, action, value); auto kind = np_ffi::internal::np_ffi_SetV0ActionResult_kind(result); @@ -587,42 +523,11 @@ } } -void V0Actions::SetContextSyncSequenceNumber(ContextSyncSeqNum seq_num) { - actions_ = - np_ffi::internal::np_ffi_V0Actions_set_context_sync_sequence_number( - actions_, seq_num.seq_num_); -} - V0Actions V0Actions::BuildNewZeroed(AdvertisementBuilderKind kind) { auto actions = np_ffi::internal::np_ffi_build_new_zeroed_V0Actions(kind); return V0Actions(actions); } -uint8_t ContextSyncSeqNum::GetAsU8() const { - return np_ffi::internal::np_ffi_ContextSyncSeqNum_as_unsigned_byte(seq_num_); -} - -absl::StatusOr<ContextSyncSeqNum> ContextSyncSeqNum::TryBuildFromU8( - uint8_t value) { - auto result = - np_ffi::internal::np_ffi_ContextSyncSeqNum_build_from_unsigned_byte( - value); - auto kind = - np_ffi::internal::np_ffi_BuildContextSyncSeqNumResult_kind(result); - switch (kind) { - case np_ffi::internal::BuildContextSyncSeqNumResultKind::Success: { - return ContextSyncSeqNum( - np_ffi::internal::np_ffi_BuildContextSyncSeqNumResult_into_SUCCESS( - result)); - } - case np_ffi::internal::BuildContextSyncSeqNumResultKind::OutOfRange: { - return absl::InvalidArgumentError( - "Attempted to build a context sync sequence number from a non-nibble " - "value."); - } - } -} - int8_t TxPower::GetAsI8() const { return np_ffi::internal::np_ffi_TxPower_as_signed_byte(tx_power_); } @@ -733,7 +638,7 @@ } } -absl::StatusOr<std::vector<uint8_t>> DeserializedV1Section::DecryptMetadata() +absl::StatusOr<std::vector<uint8_t>> DeserializedV1Section::TryDecryptMetadata() const { assert_panic(this->owning_v1_advertisement_ != nullptr); auto decrypt_result = @@ -751,7 +656,8 @@ auto kind = np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_kind(result); switch (kind) { case np_ffi::internal::GetV1IdentityDetailsResultKind::Error: { - return absl::InvalidArgumentError("Invalid handle"); + return absl::InvalidArgumentError( + "Identity details are not available for public advertisements"); } case np_ffi::internal::GetV1IdentityDetailsResultKind::Success: { return np_ffi::internal::np_ffi_GetV1IdentityDetailsResult_into_SUCCESS( @@ -812,31 +718,31 @@ const MatchedCredentialData matched_credential_data) { np_ffi::internal::V0DiscoveryCredential discovery_cred{}; CopyToRawArray(discovery_cred.key_seed, key_seed); - CopyToRawArray(discovery_cred.legacy_metadata_key_hmac, - legacy_metadata_key_hmac); + CopyToRawArray(discovery_cred.identity_token_hmac, legacy_metadata_key_hmac); this->internal_ = {discovery_cred, matched_credential_data.data_}; } V1MatchableCredential::V1MatchableCredential( const std::array<uint8_t, 32> key_seed, - const std::array<uint8_t, 32> expected_unsigned_metadata_key_hmac, - const std::array<uint8_t, 32> expected_signed_metadata_key_hmac, + const std::array<uint8_t, 32> + expected_mic_extended_salt_identity_token_hmac, + const std::array<uint8_t, 32> expected_signature_identity_token_hmac, const std::array<uint8_t, 32> pub_key, const MatchedCredentialData matched_credential_data) { np_ffi::internal::V1DiscoveryCredential discovery_cred{}; CopyToRawArray(discovery_cred.key_seed, key_seed); - CopyToRawArray(discovery_cred.expected_unsigned_metadata_key_hmac, - expected_unsigned_metadata_key_hmac); - CopyToRawArray(discovery_cred.expected_signed_metadata_key_hmac, - expected_signed_metadata_key_hmac); + CopyToRawArray(discovery_cred.expected_mic_extended_salt_identity_token_hmac, + expected_mic_extended_salt_identity_token_hmac); + CopyToRawArray(discovery_cred.expected_signature_identity_token_hmac, + expected_signature_identity_token_hmac); CopyToRawArray(discovery_cred.pub_key, pub_key); this->internal_ = {discovery_cred, matched_credential_data.data_}; } V0BroadcastCredential::V0BroadcastCredential( - std::array<uint8_t, 32> key_seed, std::array<uint8_t, 14> metadata_key) { + std::array<uint8_t, 32> key_seed, std::array<uint8_t, 14> identity_token) { CopyToRawArray(internal_.key_seed, key_seed); - CopyToRawArray(internal_.metadata_key, metadata_key); + CopyToRawArray(internal_.identity_token, identity_token); } V0AdvertisementBuilder::~V0AdvertisementBuilder() { @@ -920,6 +826,10 @@ "The advertisement contents were not of a proper size for LDT " "encryption"); } + case SerializeV0AdvertisementResultKind::UnencryptedError: { + return absl::OutOfRangeError( + "The advertisement contents did not meet the length requirements"); + } case SerializeV0AdvertisementResultKind:: InvalidAdvertisementBuilderHandle: { return absl::InvalidArgumentError( @@ -928,30 +838,10 @@ } } -[[nodiscard]] absl::StatusOr<V0AdvertisementBuilder> -V0AdvertisementBuilder::CreateV0AdvertisementBuilderResultToInternal( - np_ffi::internal::CreateV0AdvertisementBuilderResult result) { - auto kind = - np_ffi::internal::np_ffi_CreateV0AdvertisementBuilderResult_kind(result); - switch (kind) { - case CreateV0AdvertisementBuilderResultKind::Success: { - auto adv_builder = np_ffi::internal:: - np_ffi_CreateV0AdvertisementBuilderResult_into_SUCCESS(result); - return V0AdvertisementBuilder(adv_builder); - } - case CreateV0AdvertisementBuilderResultKind::NoSpaceLeft: { - return absl::ResourceExhaustedError( - "No space left to create v0 advertisement builder"); - } - } -} - -[[nodiscard]] absl::StatusOr<V0AdvertisementBuilder> -V0AdvertisementBuilder::TryCreatePublic() { +[[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreatePublic() { auto result = np_ffi::internal::np_ffi_create_v0_public_advertisement_builder(); - return V0AdvertisementBuilder::CreateV0AdvertisementBuilderResultToInternal( - result); + return V0AdvertisementBuilder(result); } template <uintptr_t N> @@ -962,15 +852,12 @@ return result; } -[[nodiscard]] absl::StatusOr<V0AdvertisementBuilder> -V0AdvertisementBuilder::TryCreateEncrypted(V0BroadcastCredential broadcast_cred, - EncryptedIdentityType identity_type, - std::array<uint8_t, 2> salt) { +[[nodiscard]] V0AdvertisementBuilder V0AdvertisementBuilder::CreateEncrypted( + V0BroadcastCredential broadcast_cred, std::array<uint8_t, 2> salt) { auto result = np_ffi::internal::np_ffi_create_v0_encrypted_advertisement_builder( - broadcast_cred.internal_, identity_type, ToFFIArray(salt)); - return V0AdvertisementBuilder::CreateV0AdvertisementBuilderResultToInternal( - result); + broadcast_cred.internal_, ToFFIArray(salt)); + return V0AdvertisementBuilder(result); } -} // namespace nearby_protocol \ No newline at end of file +} // namespace nearby_protocol
diff --git a/nearby/presence/np_cpp_ffi/sample/main.cc b/nearby/presence/np_cpp_ffi/sample/main.cc index eb0cae0..8a5c044 100644 --- a/nearby/presence/np_cpp_ffi/sample/main.cc +++ b/nearby/presence/np_cpp_ffi/sample/main.cc
@@ -14,22 +14,28 @@ #include <bitset> #include <iostream> +#include <string> +#include <utility> #include "absl/strings/escaping.h" #include "nearby_protocol.h" +#include "np_cpp_ffi_types.h" -static void SamplePanicHandler(nearby_protocol::PanicReason reason); +void SamplePanicHandler(nearby_protocol::PanicReason reason); -void HandleAdvertisementResult(nearby_protocol::DeserializeAdvertisementResult); +void HandleAdvertisementResult( + nearby_protocol::DeserializeAdvertisementResult /*result*/); -void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement); -void HandleLegibleV0Adv(nearby_protocol::LegibleDeserializedV0Advertisement); -void HandleV0IdentityKind(nearby_protocol::DeserializedV0IdentityKind); -void HandleDataElement(nearby_protocol::V0DataElement); +void HandleV0Adv(nearby_protocol::DeserializedV0Advertisement /*result*/); +void HandleLegibleV0Adv( + nearby_protocol::LegibleDeserializedV0Advertisement /*legible_adv*/); +void HandleV0IdentityKind( + nearby_protocol::DeserializedV0IdentityKind /*identity*/); +void HandleDataElement(nearby_protocol::V0DataElement /*de*/); -void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement); -void HandleV1Section(nearby_protocol::DeserializedV1Section); -void HandleV1DataElement(nearby_protocol::V1DataElement); +void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement /*adv*/); +void HandleV1Section(const nearby_protocol::DeserializedV1Section& /*section*/); +void HandleV1DataElement(nearby_protocol::V1DataElement /*de*/); int main() { auto result = @@ -45,54 +51,48 @@ std::cout << "\n========= Example V0 Adv ==========\n"; std::cout << "Hex bytes: 00031503260046\n\n"; - // Create an empty credential slab and verify that it is successful - auto cred_slab_result = nearby_protocol::CredentialSlab::TryCreate(); - if (!cred_slab_result.ok()) { - std::cout << cred_slab_result.status().ToString(); - return -1; - } + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); - // Create an empty credential book from the empty slab, and verify success. - auto cred_book_result = nearby_protocol::CredentialBook::TryCreateFromSlab( - cred_slab_result.value()); - if (!cred_book_result.ok()) { - std::cout << cred_book_result.status().ToString(); - return -1; - } - - auto v0_byte_string = + const auto* v0_byte_string = "00" // Adv Header "03" // Public DE header "1503" // Length 1 Tx Power DE with value 3 "260046"; // Length 2 Actions - auto v0_bytes = absl::HexStringToBytes(v0_byte_string); + std::string v0_bytes; + if (!absl::HexStringToBytes(v0_byte_string, &v0_bytes)) { + return -1; + } auto v0_buffer = nearby_protocol::ByteBuffer<255>::TryFromString(v0_bytes); - nearby_protocol::RawAdvertisementPayload v0_payload(v0_buffer.value()); + nearby_protocol::RawAdvertisementPayload const v0_payload(v0_buffer.value()); // Try to deserialize a V0 payload auto deserialize_v0_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - v0_payload, cred_book_result.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(v0_payload, + credential_book); HandleAdvertisementResult(std::move(deserialize_v0_result)); std::cout << "\n========= Example V1 Adv ==========\n"; std::cout << "Hex bytes: 20040326004603031505\n\n"; - auto v1_byte_string = + const auto* v1_byte_string = "20" // V1 Advertisement header "04" // Section Header "03" // Public Identity DE header "260046"; // Length 2 Actions DE - auto v1_bytes = absl::HexStringToBytes(v1_byte_string); + std::string v1_bytes; + if (!absl::HexStringToBytes(v1_byte_string, &v1_bytes)) { + return -1; + } auto v1_buffer = nearby_protocol::ByteBuffer<255>::TryFromString(v1_bytes); - nearby_protocol::RawAdvertisementPayload v1_payload(v1_buffer.value()); + nearby_protocol::RawAdvertisementPayload const v1_payload(v1_buffer.value()); // Try to deserialize a V1 payload auto deserialize_v1_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - v1_payload, cred_book_result.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(v1_payload, + credential_book); HandleAdvertisementResult(std::move(deserialize_v1_result)); std::cout << "\n========= User input sample ==========\n\n"; @@ -101,19 +101,25 @@ std::cout << "Enter the hex of the advertisement you would like to parse " "(see above examples): "; std::cin >> user_input; - auto bytes = absl::HexStringToBytes(user_input); + std::string bytes; + auto hex_result = absl::HexStringToBytes(user_input, &bytes); + if (!hex_result) { + std::cout << "Provided string is not valid hex"; + continue; + } auto buffer = nearby_protocol::ByteBuffer<255>::TryFromString(bytes); if (!buffer.ok()) { std::cout << "Too many bytes provided, must fit into a max length 255 " "byte BLE advertisement\n"; continue; } - nearby_protocol::RawAdvertisementPayload user_input_payload(buffer.value()); + nearby_protocol::RawAdvertisementPayload const user_input_payload( + buffer.value()); // Try to deserialize user input auto user_input_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - user_input_payload, cred_book_result.value()); + user_input_payload, credential_book); HandleAdvertisementResult(std::move(user_input_result)); char choice; @@ -128,7 +134,7 @@ } } -static void SamplePanicHandler(nearby_protocol::PanicReason reason) { +void SamplePanicHandler(nearby_protocol::PanicReason reason) { std::cout << "Panicking! Reason: "; switch (reason) { case nearby_protocol::PanicReason::EnumCastFailed: { @@ -143,6 +149,9 @@ std::cout << "InvalidStackDataStructure \n"; break; } + case np_ffi::internal::PanicReason::ExceededMaxHandleAllocations: + std::cout << "ExceededMaxHandleAllocations \n"; + break; } std::abort(); } @@ -182,7 +191,8 @@ HandleV0IdentityKind(legible_adv.GetIdentityKind()); auto num_des = legible_adv.GetNumberOfDataElements(); - std::cout << "\t\tAdv contains " << unsigned(num_des) << " data elements \n"; + std::cout << "\t\tAdv contains " << static_cast<unsigned>(num_des) + << " data elements \n"; auto payload = legible_adv.IntoPayload(); for (int i = 0; i < num_des; i++) { auto de_result = payload.TryGetDataElement(i); @@ -214,7 +224,8 @@ case nearby_protocol::V0DataElementKind::TxPower: { std::cout << "\t\t\tDE Type is TxPower\n"; auto tx_power = de.AsTxPower(); - std::cout << "\t\t\tpower: " << int(tx_power.GetAsI8()) << "\n"; + std::cout << "\t\t\tpower: " << static_cast<int>(tx_power.GetAsI8()) + << "\n"; return; } case nearby_protocol::V0DataElementKind::Actions: { @@ -229,11 +240,11 @@ void HandleV1Adv(nearby_protocol::DeserializedV1Advertisement adv) { auto legible_sections = adv.GetNumLegibleSections(); - std::cout << "\tAdv has " << unsigned(legible_sections) + std::cout << "\tAdv has " << static_cast<unsigned>(legible_sections) << " legible sections \n"; auto encrypted_sections = adv.GetNumUndecryptableSections(); - std::cout << "\tAdv has " << unsigned(encrypted_sections) + std::cout << "\tAdv has " << static_cast<unsigned>(encrypted_sections) << " undecryptable sections\n"; for (auto i = 0; i < legible_sections; i++) { @@ -247,7 +258,7 @@ } } -void HandleV1Section(nearby_protocol::DeserializedV1Section section) { +void HandleV1Section(const nearby_protocol::DeserializedV1Section& section) { switch (section.GetIdentityKind()) { case np_ffi::internal::DeserializedV1IdentityKind::Plaintext: { std::cout << "\t\tIdentity is Plaintext\n"; @@ -260,7 +271,8 @@ } auto num_des = section.NumberOfDataElements(); - std::cout << "\t\tSection has " << unsigned(num_des) << " data elements \n"; + std::cout << "\t\tSection has " << static_cast<unsigned>(num_des) + << " data elements \n"; for (auto i = 0; i < num_des; i++) { auto de_result = section.TryGetDataElement(i); if (!de_result.ok()) { @@ -275,7 +287,7 @@ void HandleV1DataElement(nearby_protocol::V1DataElement de) { std::cout << "\t\t\tData Element type code: " - << unsigned(de.GetDataElementTypeCode()) << "\n"; + << static_cast<unsigned>(de.GetDataElementTypeCode()) << "\n"; std::cout << "\t\t\tPayload bytes as hex: " << absl::BytesToHexString(de.GetPayload().ToString()) << "\n"; }
diff --git a/nearby/presence/np_cpp_ffi/shared/shared_test_util.cc b/nearby/presence/np_cpp_ffi/shared/shared_test_util.cc index 8f172c1..58e1d20 100644 --- a/nearby/presence/np_cpp_ffi/shared/shared_test_util.cc +++ b/nearby/presence/np_cpp_ffi/shared/shared_test_util.cc
@@ -29,6 +29,8 @@ case nearby_protocol::PanicReason::InvalidStackDataStructure: { return "InvalidStackDataStructure"; } + case np_ffi::internal::PanicReason::ExceededMaxHandleAllocations: + return "ExceededMaxHandleAllocations"; } }
diff --git a/nearby/presence/np_cpp_ffi/shared/shared_test_util.h b/nearby/presence/np_cpp_ffi/shared/shared_test_util.h index da57b63..83e79a7 100644 --- a/nearby/presence/np_cpp_ffi/shared/shared_test_util.h +++ b/nearby/presence/np_cpp_ffi/shared/shared_test_util.h
@@ -19,25 +19,27 @@ // Plaintext advertisement bytes constexpr std::array<uint8_t, 2> V0AdvEmptyBytes{0x00, 0x03}; -constexpr std::array<uint8_t, 2> V1AdvEmptyBytes{0x00, 0x20}; -constexpr std::array<uint8_t, 4> V0AdvPlaintextBytes{0x00, 0x03, 0x15, 0x03}; -constexpr std::array<uint8_t, 7> V0AdvPlaintextMultiDeBytes{ - 0x00, 0x03, 0x15, 0x05, 0x26, 0x00, 0x46, +constexpr std::array<uint8_t, 2> V1AdvEmptyBytes{0x00, 0x00}; +constexpr std::array<uint8_t, 3> V0AdvPlaintextBytes{0x00, 0x15, 0x03}; +constexpr std::array<uint8_t, 6> V0AdvPlaintextMultiDeBytes{ + 0x00, 0x15, 0x05, 0x26, 0x40, 0x40, }; -constexpr std::array<uint8_t, 5> V1AdvPlaintextBytes{0x20, 0x03, 0x03, 0x15, +constexpr std::array<uint8_t, 5> V1AdvPlaintextBytes{0x20, // Version header + 0x00, // format + 0x02, // section len + 0x15, // Tx power value 3 0x03}; // V0 encrypted advertisement data - ripped out of np_adv/tests/examples_v0.rs -constexpr std::array<uint8_t, 20> V0AdvEncryptedBytes{ - 0x00, 0x21, 0x22, 0x22, 0x85, 0xBF, 0xA8, 0x83, 0x58, 0x7C, - 0x50, 0xCF, 0x98, 0x38, 0xA7, 0x8A, 0xC0, 0x1C, 0x96, 0xF9, -}; +constexpr std::array<uint8_t, 19> V0AdvEncryptedBytes{ + 0x04, 0x22, 0x22, 0xD8, 0x22, 0x12, 0xEF, 0x16, 0xDB, 0xF8, + 0x72, 0xF2, 0xA3, 0xA7, 0xC0, 0xFA, 0x52, 0x48, 0xEC}; inline std::vector<uint8_t> V0AdvEncryptedMetadata = { - 0x26, 0xC5, 0xEA, 0xD4, 0xED, 0x58, 0xF8, 0xFC, 0xE8, 0xF4, 0xAB, 0x0C, - 0x93, 0x2B, 0x75, 0xAA, 0x74, 0x39, 0x67, 0xDB, 0x1E, 0xF2, 0x33, 0xB5, - 0x43, 0xCC, 0x94, 0xAA, 0xA3, 0xBB, 0xB9, 0x4C, 0xBF, 0x57, 0x77, 0xD0, - 0x43, 0x0C, 0x7F, 0xF7, 0x36, 0x03, 0x29, 0xE0, 0x57, 0xBA, 0x97, 0x7F, - 0xF2, 0xD1, 0x51, 0xDB, 0xC9, 0x01, 0x47, 0xE7, 0x48, 0x36, + 0x8D, 0xD4, 0x7A, 0x58, 0x47, 0x30, 0x65, 0x89, 0x06, 0x16, 0x04, 0xCA, + 0x68, 0xCE, 0xB4, 0x18, 0xA7, 0x40, 0xB8, 0x36, 0xB0, 0x94, 0xB4, 0xC0, + 0x6C, 0xAF, 0x7C, 0x4A, 0x3B, 0x68, 0x28, 0x54, 0x8F, 0x36, 0xD5, 0x68, + 0x12, 0x6C, 0xC2, 0x63, 0x31, 0x4A, 0x48, 0xE4, 0x3B, 0xB3, 0xCF, 0xD4, + 0x10, 0x49, 0x59, 0xE7, 0x2B, 0xDE, 0xEB, 0x78, 0x44, 0x68, }; inline std::string ExpectedV0DecryptedMetadata( R"({"name":"Alice","email":"alice@gmail.com"})"); @@ -46,52 +48,47 @@ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, }; -constexpr std::array<uint8_t, 32> V0AdvLegacyMetadataKeyHmac = { - 0x88, 0x33, 0xDE, 0xD5, 0x4D, 0x00, 0x92, 0xE8, 0x80, 0x70, 0xD5, - 0x1F, 0x18, 0xEC, 0x22, 0x45, 0x75, 0x7C, 0x24, 0xDF, 0xE3, 0x8C, - 0xB2, 0xDE, 0x77, 0xB6, 0x78, 0x85, 0xFC, 0xA5, 0x67, 0x4D, -}; +constexpr std::array<uint8_t, 32> V0AdvLegacyIdentityTokenHmac = { + 0x09, 0xFE, 0x9E, 0x81, 0xB7, 0x3E, 0x5E, 0xCC, 0x76, 0x59, 0x57, + 0x71, 0xE0, 0x1F, 0xFB, 0x34, 0x38, 0xE7, 0x5F, 0x24, 0xA7, 0x69, + 0x56, 0xA0, 0xB8, 0xEA, 0x67, 0xD1, 0x1C, 0x3E, 0x36, 0xFD}; // V1 encrypted advertisement data - ripped out of np_adv/tests/examples_v1.rs -constexpr std::array<uint8_t, 105> V1AdvEncryptedBytes{ - 0x20, 0x67, 0x91, 0x10, 0x08, 0xAD, 0x69, 0x46, 0x04, 0x5D, 0xAE, 0x6D, - 0xB7, 0xF7, 0x5C, 0xD3, 0xB8, 0xAC, 0xF0, 0xBF, 0x75, 0x90, 0x01, 0xBE, - 0x73, 0x33, 0xA4, 0x76, 0x84, 0x4A, 0x09, 0x0F, 0x2B, 0x99, 0x47, 0xDF, - 0x8B, 0x46, 0xCA, 0x16, 0xCE, 0x13, 0xB5, 0x6E, 0x53, 0xAE, 0x28, 0x56, - 0x44, 0x0E, 0xA6, 0x8D, 0xEB, 0xA1, 0x11, 0xAF, 0x4E, 0x1B, 0xE0, 0x8E, - 0xF5, 0xBA, 0x90, 0x4F, 0x2E, 0x94, 0xFC, 0xDE, 0xA6, 0x7F, 0x5D, 0xC8, - 0x37, 0xB7, 0xEF, 0xCA, 0xAC, 0x8B, 0x9F, 0x1B, 0xD4, 0xC6, 0x11, 0x85, - 0xD3, 0x67, 0x39, 0x32, 0xD1, 0x82, 0xCA, 0x4E, 0xB9, 0x46, 0x03, 0x83, - 0x68, 0x56, 0x0B, 0xCC, 0xFD, 0x7A, 0x2A, 0xBE, 0x07, -}; +constexpr std::array<uint8_t, 101> V1AdvEncryptedBytes{ + 0x20, 0x03, 0x9C, 0xED, 0x67, 0x93, 0x04, 0x6A, 0xBB, 0x1B, 0x1C, 0x40, + 0x45, 0x1F, 0x34, 0x6C, 0x03, 0xF3, 0xAA, 0x4F, 0x01, 0x8B, 0x7A, 0x5F, + 0x8A, 0x7B, 0x06, 0x29, 0xA4, 0x12, 0x27, 0x12, 0x63, 0xB4, 0x42, 0x76, + 0xDE, 0xE9, 0x01, 0x6D, 0xF5, 0x70, 0x1C, 0x09, 0xDF, 0xBE, 0x2E, 0x32, + 0xE5, 0x64, 0x8A, 0xDF, 0xB0, 0xB5, 0xE0, 0xC1, 0xD9, 0x76, 0x99, 0x4C, + 0x71, 0xFB, 0xB2, 0xBF, 0xA2, 0xB9, 0xC2, 0xEA, 0x95, 0xE6, 0x6B, 0xFD, + 0xD7, 0x93, 0x4D, 0xB5, 0x2D, 0xC2, 0x8D, 0x1E, 0x31, 0x32, 0x00, 0x88, + 0x38, 0xBA, 0x73, 0x39, 0x5E, 0x23, 0xC3, 0x6C, 0x2D, 0x50, 0x22, 0x5B, + 0xB5, 0xF4, 0x9C, 0x96, 0x37}; constexpr std::array<uint8_t, 32> V1AdvKeySeed = { - 0x31, 0x43, 0x63, 0x1E, 0xCA, 0xE8, 0x97, 0x4B, 0x96, 0x50, 0xCC, - 0x1C, 0x48, 0x25, 0x0E, 0x81, 0x58, 0x06, 0x81, 0x51, 0xF9, 0xEB, - 0x25, 0x23, 0x03, 0xD4, 0x97, 0x6D, 0x95, 0x19, 0x91, 0x39, -}; -constexpr std::array<uint8_t, 32> V1AdvExpectedUnsignedMetadataKeyHmac = {0}; -constexpr std::array<uint8_t, 32> V1AdvExpectedSignedMetadataKeyHmac = { - 0x1C, 0xBC, 0xEB, 0xDC, 0x17, 0xB5, 0x91, 0xE5, 0x07, 0x9D, 0x70, - 0xC1, 0xE8, 0x4B, 0xCC, 0xDB, 0x4B, 0x0F, 0x76, 0x83, 0x59, 0x62, - 0x0A, 0x2D, 0x55, 0x0B, 0x3B, 0x36, 0xA4, 0x92, 0x8B, 0x13, -}; + 0xF1, 0xEF, 0x9E, 0x34, 0xDC, 0x28, 0xBC, 0x37, 0x5B, 0x6E, 0x4A, + 0xC4, 0x52, 0xE6, 0x9C, 0xD3, 0x6D, 0xA9, 0xAB, 0x21, 0x5B, 0x02, + 0xB9, 0x10, 0x27, 0xC3, 0xA9, 0x53, 0xB5, 0x29, 0x4C, 0x36}; +constexpr std::array<uint8_t, 32> + V1AdvExpectedMicExtendedSaltIdentityTokenHmac = {0}; +constexpr std::array<uint8_t, 32> V1AdvExpectedSignatureIdentityTokenHmac = { + 0x10, 0x05, 0x45, 0x27, 0x8F, 0xE6, 0x86, 0x5B, 0x51, 0xB0, 0x39, + 0xEA, 0xB8, 0xD7, 0x5F, 0x61, 0x41, 0xDD, 0x92, 0x62, 0xDD, 0x1A, + 0x9D, 0xDA, 0x98, 0xDA, 0xF2, 0xDC, 0xA9, 0xD2, 0x45, 0x50}; constexpr std::array<uint8_t, 32> V1AdvPublicKey = { - 0x6D, 0x0D, 0xB6, 0x09, 0x10, 0xB1, 0x4E, 0xC4, 0x7E, 0x10, 0x16, - 0x14, 0x9C, 0x9F, 0xF2, 0x14, 0x0F, 0xEC, 0x53, 0x76, 0xE3, 0x07, - 0xD9, 0xD3, 0x9E, 0xAE, 0xE7, 0x45, 0x2C, 0x03, 0xEC, 0x6D, -}; + 0x39, 0xA0, 0x74, 0x81, 0x70, 0x46, 0xFF, 0x72, 0x59, 0xC7, 0x78, + 0x6C, 0x30, 0x7B, 0xC8, 0x71, 0x26, 0x34, 0xFF, 0x13, 0x61, 0x8C, + 0xE6, 0x22, 0x46, 0x62, 0x56, 0xFD, 0xC1, 0x7A, 0x01, 0xAE}; inline std::vector<uint8_t> V1AdvEncryptedMetadata = { - 0x09, 0xB8, 0xC6, 0x6B, 0x71, 0x43, 0x55, 0x4C, 0xB9, 0x9D, 0xBF, - 0xE4, 0xAF, 0x3E, 0xA2, 0x56, 0x0E, 0x6C, 0xBC, 0xDC, 0x3F, 0x3F, - 0x0D, 0x28, 0xD4, 0x50, 0xA9, 0xEA, 0xC3, 0x60, 0xB0, 0x81, 0x31, - 0xE2, 0x67, 0xB5, 0xC8, 0x15, 0x0C, 0xCA, 0x0B, 0x9B, 0x2C, 0x80, - 0xC1, 0xB1, 0xF6, 0x5F, 0xE1, 0x51, 0xF9, 0xE2, 0x23, 0x56, 0xD4, - 0x0B, 0x89, 0xA7, 0xF3, 0x4D, 0xE8, 0x79, 0x26, 0x44, 0x7E, 0x62, - 0xDE, 0x53, 0x13, 0x15, 0x3D, 0xFC, 0x04, 0x2E, 0x2D, 0x08, 0x43, - 0x2E, 0xE1, 0x96, 0xE8, 0x0F, 0xD0, 0xFC, 0xDE, 0x03, 0x86, 0x23, - 0xB6, 0x98, 0x85, 0x27, 0x67, 0xD8, 0x1D, 0xC3, 0xE2, 0xE0, 0xA4, - 0x32, 0x1A, 0x5F, 0x51, 0x0B, 0xA8, 0xD8, 0xA7, 0x23, 0xA4, 0x57, -}; + 0x7B, 0xE9, 0x66, 0x00, 0x9E, 0x14, 0x50, 0xDE, 0x96, 0xCB, 0x79, + 0x38, 0x93, 0xC5, 0x15, 0xE9, 0xC2, 0x6B, 0xE8, 0x03, 0x9F, 0x6C, + 0xCA, 0x94, 0xAD, 0x24, 0x13, 0x27, 0xC1, 0xDE, 0xBC, 0xC2, 0x29, + 0x88, 0xC0, 0xA5, 0x3B, 0xCA, 0x98, 0x4A, 0x42, 0xC3, 0xDE, 0xF5, + 0x1C, 0xAE, 0xFF, 0xC0, 0x02, 0xD2, 0xD2, 0x97, 0x8B, 0x52, 0x93, + 0x71, 0x07, 0x39, 0x87, 0x89, 0xCB, 0xCD, 0x79, 0x0A, 0x19, 0x0E, + 0x73, 0xEB, 0x24, 0xFA, 0x8F, 0x4C, 0xA7, 0xF3, 0x95, 0x0B, 0xED, + 0xEF, 0x27, 0x49, 0x8D, 0xE8, 0x7B, 0x88, 0x33, 0x16, 0x83, 0xF6, + 0xF1, 0xE6, 0x43, 0x22, 0x70, 0x70, 0xFD, 0x9B, 0xA6, 0x52, 0x35, + 0x0B, 0xBF, 0xBA, 0x0C, 0x20, 0xA3, 0x0C, 0xE7, 0xC7, 0xD0, 0x70}; inline std::string ExpectedV1DecryptedMetadata( "{\"uuid\":\"378845e1-2616-420d-86f5-674177a7504d\"," "\"display_name\":\"Alice\",\"location\":\"Wonderland\"}");
diff --git a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc index f76f396..e75d77d 100644 --- a/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/byte_buffer_tests.cc
@@ -28,7 +28,9 @@ TEST_F(NpCppTest, ByteBufferMaxLength) { // Each hex byte takes up 2 characters so length 510 string = 255 bytes of hex auto str_bytes = generate_hex_string(510); - auto bytes = absl::HexStringToBytes(str_bytes); + + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes(str_bytes, &bytes)); auto buffer = nearby_protocol::ByteBuffer< nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(bytes); ASSERT_TRUE(buffer.ok()); @@ -81,14 +83,16 @@ TEST_F(NpCppTest, ByteBufferInvalidLength) { // 256 bytes should fail auto str_bytes = generate_hex_string(512); - auto bytes = absl::HexStringToBytes(str_bytes); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes(str_bytes, &bytes)); auto buffer = nearby_protocol::ByteBuffer< nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(bytes); ASSERT_FALSE(buffer.ok()); } TEST_F(NpCppTest, ByteBufferRoundTrip) { - auto bytes = absl::HexStringToBytes("2003031503"); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes("2003031503", &bytes)); auto buffer = nearby_protocol::ByteBuffer< nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(bytes); auto string = buffer.value().ToString(); @@ -96,19 +100,22 @@ } TEST_F(NpCppTest, ByteBufferPayloadWrongSize) { - auto bytes = absl::HexStringToBytes("1111111111111111111111"); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes("1111111111111111111111", &bytes)); auto buffer = nearby_protocol::ByteBuffer<10>::TryFromString(bytes); ASSERT_FALSE(buffer.ok()); } TEST_F(NpCppTest, ByteBufferEmptyString) { - auto bytes = absl::HexStringToBytes(""); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes("", &bytes)); auto buffer = nearby_protocol::ByteBuffer<10>::TryFromString(bytes); ASSERT_TRUE(buffer.ok()); } TEST_F(NpCppTest, ByteBufferToVector) { - auto bytes = absl::HexStringToBytes("1234567890"); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes("1234567890", &bytes)); auto buffer = nearby_protocol::ByteBuffer<100>::TryFromString(bytes); auto vec = buffer.value().ToVector(); const std::vector<uint8_t> expected{0x12, 0x34, 0x56, 0x78, 0x90}; @@ -116,17 +123,21 @@ } TEST_F(NpCppTest, ByteBufferEndToEndPayloadAsString) { - const std::string bytes = absl::HexStringToBytes("2003031503"); + std::string bytes; + ASSERT_TRUE( + absl::HexStringToBytes("20" // NP Version Header V1 + "00" // Format = unencrypted + "02" // section length = 2 + "1503", // tx power value 3 + &bytes)); auto buffer = nearby_protocol::ByteBuffer< nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(bytes); ASSERT_TRUE(buffer.ok()); const nearby_protocol::RawAdvertisementPayload adv(buffer.value()); - auto credential_slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(credential_slab) - .value(); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto str = nearby_protocol::Deserializer::DeserializeAdvertisement( adv, credential_book) .IntoV1() @@ -136,6 +147,9 @@ .value() .GetPayload() .ToString(); - ASSERT_EQ(str, absl::HexStringToBytes("03")); + + std::string expected; + ASSERT_TRUE(absl::HexStringToBytes("03", &expected)); + ASSERT_EQ(str, expected); } -// NOLINTEND(readability-magic-numbers) \ No newline at end of file +// NOLINTEND(readability-magic-numbers)
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc index 32aa173..7ead975 100644 --- a/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/credential_book_tests.cc
@@ -21,31 +21,9 @@ #include "np_cpp_test.h" #include "shared_test_util.h" -TEST_F(NpCppTest, TestSetMaxCredBooks) { - auto slab1_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab1_result.ok()); - auto book1_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab1_result.value()); - ASSERT_TRUE(book1_result.ok()); - - auto slab2_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab2_result.ok()); - auto book2_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab2_result.value()); - ASSERT_TRUE(book2_result.ok()); - - auto slab3_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab3_result.ok()); - auto book3_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab3_result.value()); - - ASSERT_FALSE(book3_result.ok()); - ASSERT_TRUE(absl::IsResourceExhausted(book3_result.status())); -} - -TEST_F(NpCppTest, TestBookMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); +TEST_F(NpCppTest, TestCredBookMoveConstructor) { + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, book); @@ -76,9 +54,35 @@ ""); } -TEST_F(NpCppTest, TestBookMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); +TEST_F(NpCppTest, TestCredBookDestructor) { + nearby_protocol::CredentialSlab slab1; + auto current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.cred_slab, 1U); + nearby_protocol::CredentialBook book1(slab1); + current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.cred_book, 1U); + ASSERT_EQ(current_allocations.cred_slab, 0U); + + { + nearby_protocol::CredentialSlab slab2; + nearby_protocol::CredentialBook book2(slab2); + current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.cred_book, 2U); + } + + // After above RAII class goes out of scope, its de-allocation should be + // reflected in the handle allocation count + current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.cred_book, 1U); +} + +TEST_F(NpCppTest, TestCredBookMoveAssignment) { + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, book); @@ -86,9 +90,8 @@ nearby_protocol::DeserializeAdvertisementResultKind::V0); // create a second empty credential book - auto other_slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto other_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(other_slab).value(); + nearby_protocol::CredentialSlab other_slab; + nearby_protocol::CredentialBook other_book(other_slab); other_book = std::move(book); // new credential book should still be successful
diff --git a/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc index 719323f..ebaf874 100644 --- a/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/credential_slab_tests.cc
@@ -23,101 +23,48 @@ #include "np_cpp_test.h" // NOLINTBEGIN(readability-magic-numbers) -TEST_F(NpCppTest, TestSetMaxCredSlabs) { - auto slab1_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab1_result.ok()); - - auto slab2_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab2_result.ok()); - - auto slab3_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab3_result.ok()); - - auto slab4_result = nearby_protocol::CredentialSlab::TryCreate(); - - ASSERT_FALSE(slab4_result.ok()); - ASSERT_TRUE(absl::IsResourceExhausted(slab4_result.status())); -} - TEST_F(NpCppTest, TestSlabMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); + nearby_protocol::CredentialSlab slab; // It should be possible to move the slab into a new object // and use the moved version to successfully construct a // credential-book. nearby_protocol::CredentialSlab next_slab(std::move(slab)); + nearby_protocol::CredentialBook book(next_slab); - auto maybe_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab); - ASSERT_TRUE(maybe_book.ok()); - - // Now, both slabs should be moved-out-of, since `TryCreateFromSlab` takes + // Now, both slabs should be moved-out-of, since `CreateFromSlab` takes // ownership. Verify that this is the case, and attempts to re-use the slabs // result in an assert failure. - ASSERT_DEATH([[maybe_unused]] auto failure = - nearby_protocol::CredentialBook::TryCreateFromSlab( - slab), // NOLINT(bugprone-use-after-move) + ASSERT_DEATH([[maybe_unused]] nearby_protocol::CredentialBook failure( + slab), // NOLINT(bugprone-use-after-move) ""); - ASSERT_DEATH( - [[maybe_unused]] auto failure = - nearby_protocol::CredentialBook::TryCreateFromSlab(next_slab), - ""); -} - -TEST_F(NpCppTest, TestSlabDestructor) { - { - auto slab1_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab1_result.ok()); - - auto slab2_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab2_result.ok()); - - auto slab3_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab3_result.ok()); - - auto slab4_result = nearby_protocol::CredentialSlab::TryCreate(); - - ASSERT_FALSE(slab4_result.ok()); - ASSERT_TRUE(absl::IsResourceExhausted(slab4_result.status())); - } - - // Now that the above variables have gone out of scope we should verify that - // the destructor succeeded in cleaning up those resources - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); + ASSERT_DEATH([[maybe_unused]] nearby_protocol::CredentialBook failure( + next_slab), // NOLINT(bugprone-use-after-move) + ""); } TEST_F(NpCppTest, TestSlabMoveAssignment) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - - // create a second slab - auto other_slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(other_slab_result.ok()); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialSlab other_slab; // move assignment should override currently assigned slab with new one, // freeing the existing one. - auto other_slab = std::move(slab_result.value()); - auto maybe_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(other_slab); - ASSERT_TRUE(maybe_book.ok()); + other_slab = std::move(slab); + nearby_protocol::CredentialBook book(other_slab); // The old object should now lead to use after moved assert failure - ASSERT_DEATH([[maybe_unused]] auto failure = - nearby_protocol::CredentialBook::TryCreateFromSlab( - slab_result.value()), // NOLINT(bugprone-use-after-move) + ASSERT_DEATH([[maybe_unused]] nearby_protocol::CredentialBook failure( + slab), // NOLINT(bugprone-use-after-move) ""); // moving again should still lead to a use after moved assert failure - auto another_moved_book = std::move(slab_result.value()); - ASSERT_DEATH([[maybe_unused]] auto failure = - nearby_protocol::CredentialBook::TryCreateFromSlab( - another_moved_book), // NOLINT(bugprone-use-after-move) + auto another_moved_book = std::move(slab); + ASSERT_DEATH([[maybe_unused]] nearby_protocol::CredentialBook failure( + another_moved_book), // NOLINT(bugprone-use-after-move) ""); } TEST_F(NpCppTest, TestAddV0Credential) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); + nearby_protocol::CredentialSlab slab; uint8_t metadata[] = {1, 2, 3}; const std::span<uint8_t> metadata_span(metadata); @@ -128,18 +75,13 @@ const nearby_protocol::V0MatchableCredential v0_cred( key_seed, legacy_metadata_key_hmac, match_data); - auto add_result = slab_result.value().AddV0Credential(v0_cred); - ASSERT_EQ(add_result, absl::OkStatus()); + slab.AddV0Credential(v0_cred); } TEST_F(NpCppTest, TestAddV0CredentialAfterMoved) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; // creating a book will move the slab - auto maybe_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab_result.value()); - ASSERT_TRUE(maybe_book.ok()); + nearby_protocol::CredentialBook book(slab); uint8_t metadata[] = {1, 2, 3}; const std::span<uint8_t> metadata_span(metadata); @@ -148,15 +90,11 @@ const std::array<uint8_t, 32> legacy_metadata_key_hmac{1, 2, 3}; const nearby_protocol::V0MatchableCredential v0_cred( key_seed, legacy_metadata_key_hmac, match_data); - - ASSERT_DEATH([[maybe_unused]] auto add_result = - slab_result.value().AddV0Credential(v0_cred); - , ""); + ASSERT_DEATH(slab.AddV0Credential(v0_cred);, ""); } TEST_F(NpCppTest, TestAddV1Credential) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); + nearby_protocol::CredentialSlab slab; uint8_t metadata[] = {1, 2, 3}; const std::span<uint8_t> metadata_span(metadata); @@ -169,19 +107,14 @@ key_seed, expected_unsigned_metadata_key_hmac, expected_signed_metadata_key_hmac, pub_key, match_data); - auto add_result = slab_result.value().AddV1Credential(v1_cred); + auto add_result = slab.AddV1Credential(v1_cred); ASSERT_EQ(add_result, absl::OkStatus()); } TEST_F(NpCppTest, TestAddV1CredentialAfterMoved) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; // creating a book will move the slab - auto maybe_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab_result.value()); - ASSERT_TRUE(maybe_book.ok()); - + nearby_protocol::CredentialBook book(slab); uint8_t metadata[] = {1, 2, 3}; const std::span<uint8_t> metadata_span(metadata); const nearby_protocol::MatchedCredentialData match_data(111, metadata_span); @@ -193,16 +126,13 @@ key_seed, expected_unsigned_metadata_key_hmac, expected_signed_metadata_key_hmac, pub_key, match_data); - ASSERT_DEATH([[maybe_unused]] auto add_result = - slab_result.value().AddV1Credential(v1_cred); + ASSERT_DEATH([[maybe_unused]] auto add_result = slab.AddV1Credential(v1_cred); , ""); } // make sure the book can be populated with many credentials TEST_F(NpCppTest, TestAddManyCredentials) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; // Should be able to load the slab up with many credentials for (int i = 0; i < 500; i++) { uint8_t metadata[] = {1, 2, 3}; @@ -212,8 +142,7 @@ const std::array<uint8_t, 32> legacy_metadata_key_hmac{1, 2, 3}; const nearby_protocol::V0MatchableCredential v0_cred( key_seed, legacy_metadata_key_hmac, match_data); - auto add_result = slab_result->AddV0Credential(v0_cred); - ASSERT_EQ(add_result, absl::OkStatus()); + slab.AddV0Credential(v0_cred); const std::array<uint8_t, 32> v1_key_seed{1, 2, 3}; const std::array<uint8_t, 32> v1_expected_unsigned_metadata_key_hmac{1, 2, @@ -224,10 +153,23 @@ v1_key_seed, v1_expected_unsigned_metadata_key_hmac, v1_expected_signed_metadata_key_hmac, v1_pub_key, match_data); - auto add_v1_result = slab_result->AddV1Credential(v1_cred); + auto add_v1_result = slab.AddV1Credential(v1_cred); ASSERT_EQ(add_v1_result, absl::OkStatus()); } - ASSERT_TRUE( - nearby_protocol::CredentialBook::TryCreateFromSlab(*slab_result).ok()); + nearby_protocol::CredentialBook book(slab); +} + +TEST_F(NpCppTest, TestSlabDestructor) { + { + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialSlab slab2; + nearby_protocol::CredentialSlab slab3; + auto alloc_count = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(alloc_count.cred_slab, 3U); + } + auto alloc_count = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(alloc_count.cred_slab, 0U); } // NOLINTEND(readability-magic-numbers) \ No newline at end of file
diff --git a/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc b/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc index 37ef27a..af83461 100644 --- a/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/deserialize_result_tests.cc
@@ -24,8 +24,8 @@ #include "shared_test_util.h" TEST_F(NpCppTest, TestResultMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -56,25 +56,18 @@ } TEST_F(NpCppTest, DeserializeFromStringView) { - auto bytes = absl::HexStringToBytes("00031503"); + std::string bytes; + ASSERT_TRUE(absl::HexStringToBytes("001503", &bytes)); auto buffer = nearby_protocol::ByteBuffer< nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(bytes); ASSERT_TRUE(buffer.ok()); const nearby_protocol::RawAdvertisementPayload adv(buffer.value()); - - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - adv, maybe_credential_book.value()); - + nearby_protocol::Deserializer::DeserializeAdvertisement(adv, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); auto v0_adv = deserialize_result.IntoV0(); @@ -99,8 +92,8 @@ } TEST_F(NpCppTest, TestResultMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -137,79 +130,54 @@ const std::array<uint8_t, 1> InvalidHeaderPayloadBytes{0xFF}; const nearby_protocol::RawAdvertisementPayload InvalidHeaderPayload( (nearby_protocol::ByteBuffer<255>(InvalidHeaderPayloadBytes))); - - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - InvalidHeaderPayload, maybe_credential_book.value()); + InvalidHeaderPayload, credential_book); // Errors cannot be casted into further types ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::Error); - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, ""); - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, + ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, + ""); } TEST_F(NpCppTest, TestInvalidV0Cast) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V1); - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, + ""); } TEST_F(NpCppTest, TestInvalidV1Cast) { // Create an empty credential book and verify that is is successful - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, + ""); } TEST_F(NpCppTest, V0UseResultTwice) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V0); @@ -217,22 +185,16 @@ auto v0_adv = deserialize_result.IntoV0(); // Calling intoV0 for a second time is a programmer error and will result // in a crash. - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, + ""); } TEST_F(NpCppTest, V1UseResultTwice) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V1); @@ -240,22 +202,16 @@ auto v1_adv = deserialize_result.IntoV1(); // Calling intoV0 for a second time is a programmer error and will result // in a crash. - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, + ""); } TEST_F(NpCppTest, IntoV0AfterOutOfScope) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V0); @@ -264,22 +220,16 @@ // Calling intoV0 for a second time is a programmer error and will result // in a crash. - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV0(); }, + ""); } TEST_F(NpCppTest, IntoV1AfterOutOfScope) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V1); @@ -288,22 +238,16 @@ // Calling intoV0 for a second time is a programmer error and will result // in a crash. - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, + ""); } TEST_F(NpCppTest, V0ResultKindAfterOutOfScope) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V0); @@ -317,17 +261,11 @@ } TEST_F(NpCppTest, V1ResultKindAfterOutOfScope) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), np_ffi::internal::DeserializeAdvertisementResultKind::V1);
diff --git a/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h b/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h index 6cbf8c9..c8337a5 100644 --- a/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h +++ b/nearby/presence/np_cpp_ffi/tests/np_cpp_test.h
@@ -26,11 +26,6 @@ ASSERT_TRUE( nearby_protocol::GlobalConfig::SetPanicHandler(test_panic_handler)); panic_handler_set = true; - nearby_protocol::GlobalConfig::SetMaxNumDeserializedV0Advertisements(2); - nearby_protocol::GlobalConfig::SetMaxNumDeserializedV1Advertisements(2); - nearby_protocol::GlobalConfig::SetMaxNumCredentialSlabs(3); - nearby_protocol::GlobalConfig::SetMaxNumCredentialBooks(2); - nearby_protocol::GlobalConfig::SetMaxNumV0AdvertisementBuilders(2); } else { ASSERT_FALSE( nearby_protocol::GlobalConfig::SetPanicHandler(test_panic_handler));
diff --git a/nearby/presence/np_cpp_ffi/tests/v0_encrypted_deserialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v0_encrypted_deserialization_tests.cc index 3d74295..bd1f771 100644 --- a/nearby/presence/np_cpp_ffi/tests/v0_encrypted_deserialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v0_encrypted_deserialization_tests.cc
@@ -27,28 +27,19 @@ // NOLINTBEGIN(readability-magic-numbers) TEST_F(NpCppTest, V0PrivateIdentityDeserializationSimpleCase) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; const std::span<uint8_t> metadata_span(V0AdvEncryptedMetadata); const nearby_protocol::MatchedCredentialData match_data(123, metadata_span); - std::array<uint8_t, 32> key_seed = {}; std::fill_n(key_seed.begin(), 32, 0x11); - const nearby_protocol::V0MatchableCredential v0_cred( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data); - - auto add_result = slab_result->AddV0Credential(v0_cred); - ASSERT_EQ(add_result, absl::OkStatus()); - - auto book_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(*slab_result); - ASSERT_TRUE(book_result.ok()); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data); + slab.AddV0Credential(v0_cred); + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvEncryptedPayload, *book_result); + V0AdvEncryptedPayload, book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -66,16 +57,14 @@ auto de = payload.TryGetDataElement(0); ASSERT_TRUE(de.ok()); - auto metadata = payload.DecryptMetadata(); + auto metadata = payload.TryDecryptMetadata(); ASSERT_TRUE(metadata.ok()); ASSERT_EQ(ExpectedV0DecryptedMetadata, std::string(metadata->begin(), metadata->end())); - auto identity_details = payload.GetIdentityDetails(); + auto identity_details = payload.TryGetIdentityDetails(); ASSERT_TRUE(identity_details.ok()); - ASSERT_EQ(identity_details->cred_id, 123); - ASSERT_EQ(identity_details->identity_type, - nearby_protocol::EncryptedIdentityType::Private); + ASSERT_EQ(identity_details->cred_id, 123u); auto de_type = de->GetKind(); ASSERT_EQ(de_type, nearby_protocol::V0DataElementKind::TxPower); @@ -85,8 +74,8 @@ } nearby_protocol::CredentialBook CreateEmptyCredBook() { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); return book; } @@ -108,30 +97,22 @@ } TEST_F(NpCppTest, V0PrivateIdentityNoMatchingCreds) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; uint8_t metadata[] = {0}; const std::span<uint8_t> metadata_span(metadata); const nearby_protocol::MatchedCredentialData match_data(123, metadata_span); - // A randomly picked key seed, does NOT match what was used for the canned adv std::array<uint8_t, 32> key_seed = {}; std::fill_n(key_seed.begin(), 31, 0x11); - const nearby_protocol::V0MatchableCredential v0_cred( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data); + slab.AddV0Credential(v0_cred); - auto add_result = slab_result->AddV0Credential(v0_cred); - ASSERT_EQ(add_result, absl::OkStatus()); - - auto book_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(*slab_result); - ASSERT_TRUE(book_result.ok()); + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvEncryptedPayload, *book_result); + V0AdvEncryptedPayload, book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -146,31 +127,31 @@ // Make sure the correct credential is matched out of multiple provided TEST_F(NpCppTest, V0PrivateIdentityMultipleCredentials) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); + nearby_protocol::CredentialSlab slab; const std::span<uint8_t> metadata_span(V0AdvEncryptedMetadata); std::array<uint8_t, 32> key_seed = {}; // Non matching credential const nearby_protocol::MatchedCredentialData match_data(123, metadata_span); std::fill_n(key_seed.begin(), 32, 0x12); const nearby_protocol::V0MatchableCredential v0_cred( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data); - ASSERT_TRUE(slab.AddV0Credential(v0_cred).ok()); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data); + slab.AddV0Credential(v0_cred); // Matching credential const nearby_protocol::MatchedCredentialData match_data2(456, metadata_span); std::fill_n(key_seed.begin(), 32, 0x11); const nearby_protocol::V0MatchableCredential v0_cred2( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data2); - ASSERT_TRUE(slab.AddV0Credential(v0_cred2).ok()); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data2); + slab.AddV0Credential(v0_cred2); // Non matching credential const nearby_protocol::MatchedCredentialData match_data3(789, metadata_span); std::fill_n(key_seed.begin(), 32, 0x13); const nearby_protocol::V0MatchableCredential v0_cred3( - key_seed, V0AdvLegacyMetadataKeyHmac, match_data3); - ASSERT_TRUE(slab.AddV0Credential(v0_cred3).ok()); + key_seed, V0AdvLegacyIdentityTokenHmac, match_data3); + slab.AddV0Credential(v0_cred3); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialBook book(slab); auto legible_adv = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvEncryptedPayload, book) .IntoV0() @@ -183,10 +164,8 @@ ASSERT_TRUE(payload.TryGetDataElement(0).ok()); // Make sure the correct credential matches - auto identity_details = payload.GetIdentityDetails(); + auto identity_details = payload.TryGetIdentityDetails(); ASSERT_TRUE(identity_details.ok()); - ASSERT_EQ(identity_details->cred_id, 456); - ASSERT_EQ(identity_details->identity_type, - nearby_protocol::EncryptedIdentityType::Private); + ASSERT_EQ(identity_details->cred_id, 456u); } // NOLINTEND(readability-magic-numbers)
diff --git a/nearby/presence/np_cpp_ffi/tests/v0_encrypted_serialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v0_encrypted_serialization_tests.cc index ebc82a4..def4fb6 100644 --- a/nearby/presence/np_cpp_ffi/tests/v0_encrypted_serialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v0_encrypted_serialization_tests.cc
@@ -39,12 +39,8 @@ std::array<uint8_t, 2> salt = {}; std::fill_n(salt.begin(), 2, 0x22); - auto identity_type = nearby_protocol::EncryptedIdentityType::Private; - - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreateEncrypted( - broadcast_cred, identity_type, salt) - .value(); + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreateEncrypted( + broadcast_cred, salt); auto tx_power = nearby_protocol::TxPower::TryBuildFromI8(3).value(); auto de = nearby_protocol::V0DataElement(tx_power); @@ -59,4 +55,4 @@ ASSERT_EQ(actual, expected); } -// NOLINTEND(readability-magic-numbers) \ No newline at end of file +// NOLINTEND(readability-magic-numbers)
diff --git a/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_deserialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_deserialization_tests.cc index 4760009..42819d6 100644 --- a/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_deserialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_deserialization_tests.cc
@@ -24,8 +24,8 @@ #include "shared_test_util.h" TEST_F(NpCppTest, InvalidCast) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, book); @@ -34,18 +34,17 @@ // Now try to cast the result into the wrong type and verify the process // aborts - ASSERT_DEATH( - { [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, ""); + ASSERT_DEATH({ [[maybe_unused]] auto failure = deserialize_result.IntoV1(); }, + ""); } TEST_F(NpCppTest, V0DeserializeSingleDataElementTxPower) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab(slab); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook credential_book(slab); + auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -71,20 +70,15 @@ } TEST_F(NpCppTest, V0LengthOneActionsDataElement) { - const std::array<uint8_t, 4> V0AdvPlaintextLengthOneActions{0x00, 0x03, 0x16, - 0x00}; + const std::array<uint8_t, 3> V0AdvPlaintextLengthOneActions{0x00, 0x16, 0x00}; const nearby_protocol::RawAdvertisementPayload adv( (nearby_protocol::ByteBuffer<255>(V0AdvPlaintextLengthOneActions))); - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - adv, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(adv, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -110,20 +104,16 @@ } TEST_F(NpCppTest, V0LengthTwoActionsDataElement) { - const std::array<uint8_t, 5> V0AdvPlaintextLengthTwoActions{0x00, 0x03, 0x26, - 0xD0, 0x46}; + const std::array<uint8_t, 4> V0AdvPlaintextLengthTwoActions{0x00, 0x26, 0x40, + 0x40}; const nearby_protocol::RawAdvertisementPayload adv( (nearby_protocol::ByteBuffer<255>(V0AdvPlaintextLengthTwoActions))); - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - adv, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(adv, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -145,35 +135,24 @@ ASSERT_EQ(de.GetKind(), nearby_protocol::V0DataElementKind::Actions); auto actions = de.AsActions(); - ASSERT_EQ(actions.GetAsU32(), 0xD0460000); + ASSERT_EQ(actions.GetAsU32(), 0x40400000); - ASSERT_TRUE( - actions.HasAction(nearby_protocol::BooleanActionType::NearbyShare)); - ASSERT_TRUE(actions.HasAction(nearby_protocol::BooleanActionType::Finder)); - ASSERT_TRUE( - actions.HasAction(nearby_protocol::BooleanActionType::FastPairSass)); + ASSERT_TRUE(actions.HasAction(nearby_protocol::ActionType::CrossDevSdk)); + ASSERT_TRUE(actions.HasAction(nearby_protocol::ActionType::NearbyShare)); + ASSERT_FALSE(actions.HasAction(nearby_protocol::ActionType::ActiveUnlock)); ASSERT_FALSE( - actions.HasAction(nearby_protocol::BooleanActionType::ActiveUnlock)); - ASSERT_FALSE( - actions.HasAction(nearby_protocol::BooleanActionType::InstantTethering)); - ASSERT_FALSE(actions.HasAction(nearby_protocol::BooleanActionType::PhoneHub)); - ASSERT_FALSE( - actions.HasAction(nearby_protocol::BooleanActionType::PresenceManager)); - - ASSERT_EQ(actions.GetContextSyncSequenceNumber().GetAsU8(), 0xD); + actions.HasAction(nearby_protocol::ActionType::InstantTethering)); + ASSERT_FALSE(actions.HasAction(nearby_protocol::ActionType::PhoneHub)); } TEST_F(NpCppTest, V0MultipleDataElements) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); + auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintextMultiDe, maybe_credential_book.value()); + V0AdvPlaintextMultiDe, credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -203,28 +182,24 @@ ASSERT_EQ(second_de.GetKind(), nearby_protocol::V0DataElementKind::Actions); auto actions = second_de.AsActions(); - ASSERT_EQ(actions.GetAsU32(), (uint32_t)0x00460000); - ASSERT_EQ(actions.GetContextSyncSequenceNumber().GetAsU8(), (uint8_t)0); + ASSERT_EQ(actions.GetAsU32(), (uint32_t)0x40400000); } TEST_F(NpCppTest, V0EmptyPayload) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); + auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvEmpty, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvEmpty, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::Error); } TEST_F(NpCppTest, TestV0AdvMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -251,8 +226,8 @@ } TEST_F(NpCppTest, TestV0AdvMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -288,56 +263,37 @@ nearby_protocol::CredentialBook &book) { auto adv = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); + assert(adv.GetKind() == + np_ffi::internal::DeserializeAdvertisementResultKind::V0); return adv; } TEST_F(NpCppTest, V0AdvDestructor) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto book_result = nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(book_result.ok()); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); { - auto deserialize_result = CreateAdv(book_result.value()); - auto deserialize_result2 = CreateAdv(book_result.value()); - // Deserialize 2 advertisements, which will take up 2 slots in the handle - // map - ASSERT_EQ(deserialize_result.GetKind(), - np_ffi::internal::DeserializeAdvertisementResultKind::V0); - ASSERT_EQ(deserialize_result2.GetKind(), - np_ffi::internal::DeserializeAdvertisementResultKind::V0); - - // Going over max amount should result in error - auto deserialize_result3 = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book_result.value()); - ASSERT_EQ(deserialize_result3.GetKind(), - np_ffi::internal::DeserializeAdvertisementResultKind::Error); + auto deserialize_result = CreateAdv(book); + auto deserialize_result2 = CreateAdv(book); + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 2U); // Calling IntoV0() should move the underlying resources into the v0 // object when both go out of scope only one should be freed auto v0_adv = deserialize_result.IntoV0(); } - - // Now that the first v0 adv is out of scope, it should be de-allocated which - // will create room for one more to be created. - auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book_result.value()); - ASSERT_EQ(deserialize_result.GetKind(), - np_ffi::internal::DeserializeAdvertisementResultKind::V0); + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 0U); } TEST_F(NpCppTest, V0AdvUseAfterMove) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); + auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -353,8 +309,8 @@ } TEST_F(NpCppTest, TestLegibleAdvMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -391,8 +347,8 @@ } TEST_F(NpCppTest, TestLegibleAdvMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -436,19 +392,20 @@ auto adv = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); auto v0_adv = adv.IntoV0(); - return v0_adv.IntoLegible(); + auto legible = v0_adv.IntoLegible(); + assert(legible.GetIdentityKind() == + nearby_protocol::DeserializedV0IdentityKind::Plaintext); + assert(legible.GetNumberOfDataElements() == 1U); + return legible; } TEST_F(NpCppTest, V0LegibleAdvUseAfterMove) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto legible_adv = CreateLegibleAdv(book); // Should be able to use the valid legible adv even though its original parent // is now out of scope. - ASSERT_EQ(legible_adv.GetIdentityKind(), - nearby_protocol::DeserializedV0IdentityKind::Plaintext); - ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1); [[maybe_unused]] auto payload = legible_adv.IntoPayload(); // now that the legible adv has moved into the payload it should no longer be @@ -462,32 +419,19 @@ } TEST_F(NpCppTest, LegibleAdvDestructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); { auto legible_adv = CreateLegibleAdv(book); auto legible_adv2 = CreateLegibleAdv(book); - - // check that legible advs are valid. - ASSERT_EQ(legible_adv.GetIdentityKind(), - nearby_protocol::DeserializedV0IdentityKind::Plaintext); - ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1); - ASSERT_EQ(legible_adv2.GetIdentityKind(), - nearby_protocol::DeserializedV0IdentityKind::Plaintext); - ASSERT_EQ(legible_adv2.GetNumberOfDataElements(), 1); - - // allocation slots should be full - ASSERT_EQ(nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book) - .GetKind(), - nearby_protocol::DeserializeAdvertisementResultKind::Error); + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 2U); } - - // Verify the handle was de-allocated when legible adv went out of scope - auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book); - ASSERT_EQ(result.GetKind(), - nearby_protocol::DeserializeAdvertisementResultKind::V0); + // Verify the handles were de-allocated when legible advs went out of scope + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 0U); } nearby_protocol::V0Payload CreatePayload( @@ -496,35 +440,9 @@ return legible_adv.IntoPayload(); } -TEST_F(NpCppTest, V0PayloadDestructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); - { - auto payload = CreatePayload(book); - auto payload2 = CreatePayload(book); - - // check that payload adv is valid even though its parent is out of scope - ASSERT_TRUE(payload.TryGetDataElement(0).ok()); - ASSERT_TRUE(payload2.TryGetDataElement(0).ok()); - - // allocation slots should be full - ASSERT_EQ(nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book) - .GetKind(), - nearby_protocol::DeserializeAdvertisementResultKind::Error); - } - - // Now that the payload is out of scope its destructor should have been called - // freeing the parent handle - auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, book); - ASSERT_EQ(result.GetKind(), - nearby_protocol::DeserializeAdvertisementResultKind::V0); -} - TEST_F(NpCppTest, TestV0PayloadMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -552,8 +470,8 @@ } TEST_F(NpCppTest, TestV0PayloadMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V0AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -585,16 +503,34 @@ ""); } +TEST_F(NpCppTest, V0PayloadDestructor) { + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); + { + auto payload = CreatePayload(book); + auto payload2 = CreatePayload(book); + + // check that payload adv is valid even though its parent is out of scope + ASSERT_TRUE(payload.TryGetDataElement(0).ok()); + ASSERT_TRUE(payload2.TryGetDataElement(0).ok()); + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 2U); + } + + // Verify the handle was de-allocated when legible advs went out of scope + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.v0_payload, 0U); +} + TEST_F(NpCppTest, InvalidDataElementCast) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); + auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0); @@ -618,15 +554,12 @@ } TEST_F(NpCppTest, InvalidDataElementIndex) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); + auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V0AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V0AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V0);
diff --git a/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_serialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_serialization_tests.cc index 0ce4d24..ca28233 100644 --- a/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_serialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v0_unencrypted_serialization_tests.cc
@@ -28,45 +28,27 @@ ASSERT_FALSE(out_of_range_result.ok()); } -TEST_F(NpCppTest, ContextSyncSeqNumMustBeInRange) { - // Check that out-of-range fails - auto out_of_range_result = - nearby_protocol::ContextSyncSeqNum::TryBuildFromU8(17); - ASSERT_FALSE(out_of_range_result.ok()); - - // Check that if it's in range, we can get a context sync seq num and set it - // appropriately within an actions field. - auto actions = nearby_protocol::V0Actions::BuildNewZeroed( - nearby_protocol::AdvertisementBuilderKind::Public); - auto seq_num = nearby_protocol::ContextSyncSeqNum::TryBuildFromU8(15).value(); - actions.SetContextSyncSequenceNumber(seq_num); - ASSERT_EQ(actions.GetContextSyncSequenceNumber().GetAsU8(), - seq_num.GetAsU8()); -} - TEST_F(NpCppTest, V0UnencryptedActionFlavorMustMatch) { auto actions = nearby_protocol::V0Actions::BuildNewZeroed( nearby_protocol::AdvertisementBuilderKind::Public); // Try to set an encrypted-only action. - auto mismatch_result = actions.TrySetAction( - nearby_protocol::BooleanActionType::InstantTethering, true); + auto mismatch_result = + actions.TrySetAction(nearby_protocol::ActionType::InstantTethering, true); ASSERT_FALSE(mismatch_result.ok()); // Verify that nothing changed about the actions. - ASSERT_EQ(actions.GetAsU32(), 0); + ASSERT_EQ(actions.GetAsU32(), 0u); // Try again, but with a plaintext-compatible action. - auto success_result = actions.TrySetAction( - nearby_protocol::BooleanActionType::NearbyShare, true); + auto success_result = + actions.TrySetAction(nearby_protocol::ActionType::NearbyShare, true); ASSERT_TRUE(success_result.ok()); - ASSERT_TRUE( - actions.HasAction(nearby_protocol::BooleanActionType::NearbyShare)); + ASSERT_TRUE(actions.HasAction(nearby_protocol::ActionType::NearbyShare)); } // Corresponds to V0DeserializeSingleDataElementTxPower TEST_F(NpCppTest, V0SerializeSingleDataElementTxPower) { - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreatePublic(); auto tx_power = nearby_protocol::TxPower::TryBuildFromI8(3).value(); auto de = nearby_protocol::V0DataElement(tx_power); @@ -78,8 +60,7 @@ auto actual = serialized_bytes.ToVector(); const std::vector<uint8_t> expected{ - 0x00, // Adv Header - 0x03, // Public DE header + 0x00, // Version header 0x15, 0x03 // Length 1 Tx Power DE with value 3 }; ASSERT_EQ(actual, expected); @@ -87,8 +68,7 @@ // Corresponds to V0DeserializeLengthOneActionsDataElement TEST_F(NpCppTest, V0SerializeLengthOneActionsDataElement) { - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreatePublic(); auto actions = nearby_protocol::V0Actions::BuildNewZeroed( nearby_protocol::AdvertisementBuilderKind::Public); auto de = nearby_protocol::V0DataElement(actions); @@ -100,8 +80,7 @@ auto actual = serialized_bytes.ToVector(); const std::vector<uint8_t> expected{ - 0x00, // Adv Header - 0x03, // Public DE header + 0x00, // Version header 0x16, 0x00 // Length 1 Actions DE }; @@ -110,25 +89,16 @@ // Corresponds to V0DeserializeLengthTwoActionsDataElement TEST_F(NpCppTest, V0SerializeLengthTwoActionsDataElement) { - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreatePublic(); auto actions = nearby_protocol::V0Actions::BuildNewZeroed( nearby_protocol::AdvertisementBuilderKind::Public); ASSERT_TRUE( - actions - .TrySetAction(nearby_protocol::BooleanActionType::NearbyShare, true) + actions.TrySetAction(nearby_protocol::ActionType::NearbyShare, true) .ok()); ASSERT_TRUE( - actions.TrySetAction(nearby_protocol::BooleanActionType::Finder, true) + actions.TrySetAction(nearby_protocol::ActionType::CrossDevSdk, true) .ok()); - ASSERT_TRUE( - actions - .TrySetAction(nearby_protocol::BooleanActionType::FastPairSass, true) - .ok()); - auto seq_num = - nearby_protocol::ContextSyncSeqNum::TryBuildFromU8(0xD).value(); - actions.SetContextSyncSequenceNumber(seq_num); auto de = nearby_protocol::V0DataElement(actions); @@ -139,51 +109,8 @@ auto actual = serialized_bytes.ToVector(); const std::vector<uint8_t> expected{ - 0x00, // Adv Header - 0x03, // Public DE header - 0x26, 0xD0, 0x46 // Length 2 Actions DE - }; - - ASSERT_EQ(actual, expected); -} -// Corresponds to V0DeserializeMultipleDataElements -TEST_F(NpCppTest, V0SerializeMultipleDataElements) { - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); - - auto tx_power = nearby_protocol::TxPower::TryBuildFromI8(5).value(); - auto tx_power_de = nearby_protocol::V0DataElement(tx_power); - auto add_tx_power_de_result = adv_builder.TryAddDE(tx_power_de); - ASSERT_TRUE(add_tx_power_de_result.ok()); - - auto actions = nearby_protocol::V0Actions::BuildNewZeroed( - nearby_protocol::AdvertisementBuilderKind::Public); - - ASSERT_TRUE( - actions - .TrySetAction(nearby_protocol::BooleanActionType::NearbyShare, true) - .ok()); - ASSERT_TRUE( - actions.TrySetAction(nearby_protocol::BooleanActionType::Finder, true) - .ok()); - ASSERT_TRUE( - actions - .TrySetAction(nearby_protocol::BooleanActionType::FastPairSass, true) - .ok()); - - auto actions_de = nearby_protocol::V0DataElement(actions); - - auto add_actions_de_result = adv_builder.TryAddDE(actions_de); - ASSERT_TRUE(add_actions_de_result.ok()); - - auto serialized_bytes = adv_builder.TrySerialize().value(); - auto actual = serialized_bytes.ToVector(); - - const std::vector<uint8_t> expected{ - 0x00, // Adv Header - 0x03, // Public DE header - 0x15, 0x05, // Tx Power value 5 - 0x26, 0x00, 0x46, // Length 2 Actions + 0x00, // Version header + 0x26, 0x40, 0x40 // Length 2 Actions DE }; ASSERT_EQ(actual, expected); @@ -192,14 +119,13 @@ // TODO: Reinstate this test. // TEST_F(NpCppTest, V0SerializeEmptyPayload) { // auto adv_builder = -// nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); auto +// nearby_protocol::V0AdvertisementBuilder::CreatePublic(); auto // serialize_result = adv_builder.TrySerialize(); // ASSERT_FALSE(serialize_result.ok()); //} TEST_F(NpCppTest, TestV0AdvBuilderMoveConstructor) { - auto adv_builder = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreatePublic(); // Move it, and ensure it's still valid. nearby_protocol::V0AdvertisementBuilder moved_adv_builder( std::move(adv_builder)); @@ -227,16 +153,18 @@ { // Get us up to the limit on the number of adv builders auto adv_builder_one = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); + nearby_protocol::V0AdvertisementBuilder::CreatePublic(); auto adv_builder_two = - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().value(); - // Assert that we're at the limit - ASSERT_FALSE( - nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().ok()); + nearby_protocol::V0AdvertisementBuilder::CreatePublic(); + auto current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.v0_advertisement_builder, 2U); // Destructors should run. } // The space from the adv builders should've been reclaimed now. - ASSERT_TRUE(nearby_protocol::V0AdvertisementBuilder::TryCreatePublic().ok()); + auto current_allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(current_allocations.v0_advertisement_builder, 0U); } // NOLINTEND(readability-magic-numbers)
diff --git a/nearby/presence/np_cpp_ffi/tests/v1_encrypted_deserialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v1_encrypted_deserialization_tests.cc index 825b36c..65b9730 100644 --- a/nearby/presence/np_cpp_ffi/tests/v1_encrypted_deserialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v1_encrypted_deserialization_tests.cc
@@ -15,7 +15,6 @@ #include <array> #include <cstdint> #include <span> -#include <string> #include <vector> #include "absl/status/status.h" @@ -26,26 +25,20 @@ #include "shared_test_util.h" TEST_F(NpCppTest, V1PrivateIdentitySimpleCase) { - auto slab_result = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(slab_result.ok()); - + nearby_protocol::CredentialSlab slab; const std::span<uint8_t> metadata_span(V1AdvEncryptedMetadata); const nearby_protocol::MatchedCredentialData match_data(123, metadata_span); - const nearby_protocol::V1MatchableCredential v1_cred( - V1AdvKeySeed, V1AdvExpectedUnsignedMetadataKeyHmac, - V1AdvExpectedSignedMetadataKeyHmac, V1AdvPublicKey, match_data); + V1AdvKeySeed, V1AdvExpectedMicExtendedSaltIdentityTokenHmac, + V1AdvExpectedSignatureIdentityTokenHmac, V1AdvPublicKey, match_data); - auto add_result = slab_result->AddV1Credential(v1_cred); + auto add_result = slab.AddV1Credential(v1_cred); ASSERT_EQ(add_result, absl::OkStatus()); - auto book_result = - nearby_protocol::CredentialBook::TryCreateFromSlab(*slab_result); - ASSERT_TRUE(book_result.ok()); - + nearby_protocol::CredentialBook book(slab); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvEncrypted, - *book_result); + book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V1); @@ -59,28 +52,27 @@ nearby_protocol::DeserializedV1IdentityKind::Decrypted); ASSERT_EQ(section->NumberOfDataElements(), 1); - auto metadata = section->DecryptMetadata(); + auto metadata = section->TryDecryptMetadata(); ASSERT_TRUE(metadata.ok()); ASSERT_EQ(ExpectedV1DecryptedMetadata, std::string(metadata->begin(), metadata->end())); auto identity_details = section->GetIdentityDetails(); ASSERT_TRUE(identity_details.ok()); - ASSERT_EQ(identity_details->cred_id, 123); + ASSERT_EQ(identity_details->cred_id, 123U); ASSERT_EQ(identity_details->verification_mode, nearby_protocol::V1VerificationMode::Signature); - ASSERT_EQ(identity_details->identity_type, - nearby_protocol::EncryptedIdentityType::Private); auto de = section->TryGetDataElement(0); ASSERT_TRUE(de.ok()); - ASSERT_EQ(de->GetDataElementTypeCode(), 5); + ASSERT_EQ(de->GetDataElementTypeCode(), 5U); ASSERT_EQ(de->GetPayload().ToVector(), std::vector<uint8_t>{7}); auto offset = de->GetOffset(); auto derived_salt = section->DeriveSaltForOffset(offset); ASSERT_TRUE(derived_salt.ok()); - const std::array<uint8_t, 16> expected = { - 94, 154, 245, 152, 164, 22, 131, 157, 8, 79, 28, 77, 236, 57, 17, 97}; + const std::array<uint8_t, 16> expected = {0xD5, 0x63, 0x47, 0x39, 0x77, 0x84, + 0x38, 0xF2, 0x91, 0xBC, 0x24, 0x21, + 0xAD, 0x80, 0x88, 0x16}; ASSERT_EQ(*derived_salt, expected); -} \ No newline at end of file +}
diff --git a/nearby/presence/np_cpp_ffi/tests/v1_unencrypted_deserialization_tests.cc b/nearby/presence/np_cpp_ffi/tests/v1_unencrypted_deserialization_tests.cc index f7e233b..4f50e0c 100644 --- a/nearby/presence/np_cpp_ffi/tests/v1_unencrypted_deserialization_tests.cc +++ b/nearby/presence/np_cpp_ffi/tests/v1_unencrypted_deserialization_tests.cc
@@ -24,16 +24,12 @@ #include "shared_test_util.h" TEST_F(NpCppTest, V1SimpleTestCase) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); + nearby_protocol::CredentialSlab credential_slab; + nearby_protocol::CredentialBook credential_book(credential_slab); auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvPlaintext, maybe_credential_book.value()); + nearby_protocol::Deserializer::DeserializeAdvertisement(V1AdvPlaintext, + credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V1); @@ -66,8 +62,8 @@ } TEST_F(NpCppTest, TestV1AdvMoveConstructor) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V1AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -102,8 +98,8 @@ } TEST_F(NpCppTest, TestV1AdvMoveAssignment) { - auto slab = nearby_protocol::CredentialSlab::TryCreate().value(); - auto book = nearby_protocol::CredentialBook::TryCreateFromSlab(slab).value(); + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); auto result = nearby_protocol::Deserializer::DeserializeAdvertisement( V1AdvPlaintext, book); ASSERT_EQ(result.GetKind(), @@ -161,44 +157,43 @@ } TEST_F(NpCppTest, TestSectionOwnership) { - auto maybe_credential_slab = nearby_protocol::CredentialSlab::TryCreate(); - ASSERT_TRUE(maybe_credential_slab.ok()); - auto maybe_credential_book = - nearby_protocol::CredentialBook::TryCreateFromSlab( - maybe_credential_slab.value()); - ASSERT_TRUE(maybe_credential_book.ok()); - + nearby_protocol::CredentialSlab slab; + nearby_protocol::CredentialBook book(slab); { - auto section = GetSection(maybe_credential_book.value()); + auto section = GetSection(book); ASSERT_EQ(section.GetIdentityKind(), nearby_protocol::DeserializedV1IdentityKind::Plaintext); ASSERT_EQ(section.NumberOfDataElements(), 1); ASSERT_TRUE(section.TryGetDataElement(0).ok()); - auto section2 = GetSection(maybe_credential_book.value()); + auto section2 = GetSection(book); ASSERT_EQ(section2.GetIdentityKind(), nearby_protocol::DeserializedV1IdentityKind::Plaintext); ASSERT_EQ(section2.NumberOfDataElements(), 1); ASSERT_TRUE(section2.TryGetDataElement(0).ok()); - ASSERT_FALSE(TryDeserializeNewV1Adv(maybe_credential_book.value())); + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.legible_v1_sections, 2U); } - // now that the section has gone out of scope, deserializing a new adv should - // succeed - ASSERT_TRUE(TryDeserializeNewV1Adv(maybe_credential_book.value())); + // now that the section has gone out of scope the allocation should be + // released + auto allocations = + nearby_protocol::GlobalConfig::GetCurrentHandleAllocationCount(); + ASSERT_EQ(allocations.legible_v1_sections, 0U); } /* * Multiple sections are not supported in plaintext advertisements * TODO Update the below test to use encrypted sections TEST(NpCppTest, V1MultipleSections) { - auto maybe_credential_book = nearby_protocol::CredentialBook::TryCreate(); - ASSERT_TRUE(maybe_credential_book.ok()); + auto credential_book = nearby_protocol::CredentialBook::Create(); + ASSERT_TRUE(credential_book.ok()); auto deserialize_result = nearby_protocol::Deserializer::DeserializeAdvertisement( - V1AdvMultipleSections, maybe_credential_book.value()); + V1AdvMultipleSections, credential_book); ASSERT_EQ(deserialize_result.GetKind(), nearby_protocol::DeserializeAdvertisementResultKind::V1);
diff --git a/nearby/presence/np_ed25519/src/lib.rs b/nearby/presence/np_ed25519/src/lib.rs index fe2ab5a..b5123e1 100644 --- a/nearby/presence/np_ed25519/src/lib.rs +++ b/nearby/presence/np_ed25519/src/lib.rs
@@ -21,101 +21,34 @@ #![no_std] use array_view::ArrayView; -use crypto_provider::ed25519::{ - Ed25519Provider, KeyPair as _, PrivateKey, PublicKey as _, RawPrivateKey, RawPrivateKeyPermit, - RawPublicKey, RawSignature, Signature as _, SignatureError, -}; -use crypto_provider::CryptoProvider; +use crypto_provider::ed25519::{Ed25519Provider, PrivateKey, PublicKey, Signature, SignatureError}; use sink::{Sink, SinkWriter}; use tinyvec::ArrayVec; -/// Convenient type-alias for a crypto-provider's Ed25519 key-pair -type CpKeyPair<C> = <<C as CryptoProvider>::Ed25519 as Ed25519Provider>::KeyPair; - -/// Type-alias for the Ed25519 public key type -type CpPublicKey<C> = <<C as CryptoProvider>::Ed25519 as Ed25519Provider>::PublicKey; - -/// Type-alias for the Ed25519 signature type -type CpSignature<C> = <<C as CryptoProvider>::Ed25519 as Ed25519Provider>::Signature; - /// Maximum length of the combined (context len byte) + (context bytes) + (signing payload) /// byte-array which an ed25519 signature will be computed over. This is deliberately /// chosen to be large enough to incorporate an entire v1 adv as the signing payload. pub const MAX_SIGNATURE_BUFFER_LEN: usize = 512; -/// Representation of an Ed25519 key-pair using the given -/// [`CryptoProvider`] to back its implementation. -/// Contains both the public and secret halves of an -/// asymmetric key, and so it may be used to -/// both sign and verify message signatures. -pub struct KeyPair<C: CryptoProvider>(CpKeyPair<C>); - -impl<C: CryptoProvider> KeyPair<C> { - /// Returns the `KeyPair`'s private key bytes. - /// This method is only usable in situations where - /// the caller has permission to handle the raw bytes - /// of a private key. - pub fn raw_private_key(&self, permit: &RawPrivateKeyPermit) -> RawPrivateKey { - self.0.raw_private_key(permit) - } - - /// Builds this key-pair from an array of its private key bytes in the format - /// yielded by `private_key`. - /// This method is only usable in situations where - /// the caller has permission to handle the raw bytes - /// of a private key. - pub fn from_raw_private_key(private_key: &RawPrivateKey, permit: &RawPrivateKeyPermit) -> Self { - Self(CpKeyPair::<C>::from_raw_private_key(private_key, permit)) - } - - /// Returns the private key of this key-pair. - pub fn private_key(&self) -> PrivateKey { - self.0.private_key() - } - - /// Builds this key-pair from a private key. - pub fn from_private_key(private_key: &PrivateKey) -> Self { - Self(CpKeyPair::<C>::from_private_key(private_key)) - } - - /// Sign the given message with the given context and - /// return a digital signature. The message is represented - /// using a [`SinkWriter`] to allow the caller to construct - /// the payload to sign without requiring a fully-assembled - /// payload available as a slice. - /// - /// If the message writer writes too much data (greater than 256 bytes), - /// this will return `None` instead of a valid signature, - /// and so uses in `np_adv` will use `.expect` on the returned value - /// to indicate that this length constraint has been considered. - pub fn sign_with_context<W: SinkWriter<DataType = u8>>( - &self, - context: &SignatureContext, - msg_writer: W, - ) -> Option<Signature<C>> { - let mut buffer = context.create_signature_buffer(); - buffer.try_extend_from_writer(msg_writer).map(|_| Signature(self.0.sign(buffer.as_ref()))) - } - - /// Gets the public key of this key-pair - pub fn public(&self) -> PublicKey<C> { - PublicKey { public_key: self.0.public() } - } - - /// Generates an ed25519 keypair from a CSPRNG - /// generate is not available in `no-std` - #[cfg(feature = "std")] - pub fn generate() -> Self { - Self(CpKeyPair::<C>::generate()) - } +/// Sign the given message with the given context and +/// return a digital signature. The message is represented +/// using a [`SinkWriter`] to allow the caller to construct +/// the payload to sign without requiring a fully-assembled +/// payload available as a slice. +/// +/// If the message writer writes too much data (greater than 256 bytes), +/// this will return `None` instead of a valid signature, +/// and so uses in `np_adv` will use `.expect` on the returned value +/// to indicate that this length constraint has been considered. +pub fn sign_with_context<E: Ed25519Provider, W: SinkWriter<DataType = u8>>( + private_key: &PrivateKey, + context: &SignatureContext, + msg_writer: W, +) -> Option<Signature> { + let mut buffer = context.create_signature_buffer(); + buffer.try_extend_from_writer(msg_writer).map(|_| private_key.sign::<E>(buffer.as_ref())) } -/// Error raised when attempting to deserialize a key-pair -/// from a byte-array, but the bytes do not represent a valid -/// ed25519 key-pair -#[derive(Debug)] -pub struct InvalidKeyPairBytes; - /// Errors yielded when attempting to verify an ed25519 signature. #[derive(Debug, PartialEq, Eq)] pub enum SignatureVerificationError { @@ -131,104 +64,38 @@ } } -/// Representation of an Ed25519 public key used for -/// signature verification. -pub struct PublicKey<C: CryptoProvider> { - public_key: CpPublicKey<C>, -} - -impl<C: CryptoProvider> PublicKey<C> { - /// Constructs a public key for NP adv signature verification - /// from a public key under the given crypto-provider - pub fn new(public_key: CpPublicKey<C>) -> Self { - Self { public_key } - } - /// Succeeds if the signature was a valid signature created via the corresponding - /// keypair to this public key using the given [`SignatureContext`] on the given - /// message payload. The message payload is represented - /// using a [`SinkWriter`] to allow the caller to construct - /// the payload to sign without requiring a fully-assembled - /// payload available as a slice. - /// - /// If the message writer writes too much data (greater than 256 bytes), - /// this will return `None` instead of a valid signature, - /// and so uses in `np_adv` will use `.expect` on the returned value - /// to indicate that this length constraint has been considered. - pub fn verify_signature_with_context<W: SinkWriter<DataType = u8>>( - &self, - context: &SignatureContext, - msg_writer: W, - signature: &Signature<C>, - ) -> Result<(), SignatureVerificationError> { - let mut buffer = context.create_signature_buffer(); - let maybe_write_success = buffer.try_extend_from_writer(msg_writer); - match maybe_write_success { - Some(_) => { - self.public_key.verify_strict(buffer.as_ref(), &signature.0)?; - Ok(()) - } - None => Err(SignatureVerificationError::PayloadTooBig), +/// Succeeds if the signature was a valid signature created via the corresponding +/// keypair to this public key using the given [`SignatureContext`] on the given +/// message payload. The message payload is represented +/// using a [`SinkWriter`] to allow the caller to construct +/// the payload to sign without requiring a fully-assembled +/// payload available as a slice. +/// +/// If the message writer writes too much data (greater than 256 bytes), +/// this will return `None` instead of a valid signature, +/// and so uses in `np_adv` will use `.expect` on the returned value +/// to indicate that this length constraint has been considered. +pub fn verify_signature_with_context<E: Ed25519Provider, W: SinkWriter<DataType = u8>>( + public_key: &PublicKey, + context: &SignatureContext, + msg_writer: W, + signature: Signature, +) -> Result<(), SignatureVerificationError> { + let mut buffer = context.create_signature_buffer(); + let maybe_write_success = buffer.try_extend_from_writer(msg_writer); + match maybe_write_success { + Some(_) => { + public_key.verify_strict::<E>(buffer.as_ref(), signature)?; + Ok(()) } - } - - /// Builds an ed25519 public key from an array of bytes in - /// the format yielded by `to_bytes`. - pub fn from_bytes(bytes: &RawPublicKey) -> Result<Self, InvalidPublicKeyBytes> { - CpPublicKey::<C>::from_bytes(bytes) - .map(|public_key| Self { public_key }) - .map_err(|_| InvalidPublicKeyBytes) - } - - /// Yields the bytes of this ed25519 public key - pub fn to_bytes(&self) -> RawPublicKey { - self.public_key.to_bytes() - } -} - -impl<C: CryptoProvider> Clone for PublicKey<C> { - fn clone(&self) -> Self { - #[allow(clippy::expect_used)] - Self::from_bytes(&self.to_bytes()).expect("This should always succeed since self will always contain valid public key bytes, which is verified on creation") - } -} - -/// Error raised when attempting to deserialize a public key -/// from a byte-array, but the bytes do not represent a valid -/// ed25519 public key -#[derive(Debug)] -pub struct InvalidPublicKeyBytes; - -/// Representation of an Ed25519 message signature, -/// which can be checked against a [`PublicKey`] -/// for validity. -pub struct Signature<C: CryptoProvider>(CpSignature<C>); - -impl<C: CryptoProvider> Signature<C> { - /// Returns a slice of the signature bytes - pub fn to_bytes(&self) -> RawSignature { - self.0.to_bytes() - } -} - -/// Error raised when attempting to construct a [`Signature`] -/// from a byte-array which is not of the proper length or format. -#[derive(Debug)] -pub struct InvalidSignatureBytes; - -impl<C: CryptoProvider> TryFrom<&[u8]> for Signature<C> { - type Error = InvalidSignatureBytes; - fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> { - bytes - .try_into() - .map(|sig| Self(CpSignature::<C>::from_bytes(sig))) - .map_err(|_| InvalidSignatureBytes) + None => Err(SignatureVerificationError::PayloadTooBig), } } /// Minimum length (in bytes) for a [`SignatureContext`] (which cannot be empty). pub const MIN_SIGNATURE_CONTEXT_LEN: usize = 1; -/// Maximum length (in bytes) for a [`SignatureContext`] (which uses a 8-bit length field). +/// Maximum length (in bytes) for a [`SignatureContext`] (which uses an 8-bit length field). pub const MAX_SIGNATURE_CONTEXT_LEN: usize = 255; /// (Non-empty) context bytes to use in the construction of NP's
diff --git a/nearby/presence/np_ffi_core/Cargo.toml b/nearby/presence/np_ffi_core/Cargo.toml index a6b21b0..7c3c112 100644 --- a/nearby/presence/np_ffi_core/Cargo.toml +++ b/nearby/presence/np_ffi_core/Cargo.toml
@@ -18,6 +18,8 @@ crypto_provider_default = { workspace = true, default-features = false } lock_adapter.workspace = true lazy_static.workspace = true +strum.workspace = true +strum_macros.workspace = true [features] default = ["rustcrypto"]
diff --git a/nearby/presence/np_ffi_core/src/common.rs b/nearby/presence/np_ffi_core/src/common.rs index e90a072..592e1cd 100644 --- a/nearby/presence/np_ffi_core/src/common.rs +++ b/nearby/presence/np_ffi_core/src/common.rs
@@ -18,11 +18,10 @@ use crypto_provider::{CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; use handle_map::HandleNotPresentError; -use lock_adapter::std::{RwLock, RwLockWriteGuard}; +use lock_adapter::stdlib::{RwLock, RwLockWriteGuard}; use lock_adapter::RwLock as _; -use std::string::String; -pub(crate) const DEFAULT_MAX_HANDLES: u32 = u32::MAX - 1; +const MAX_HANDLES: u32 = u32::MAX - 1; /// Configuration for top-level constants to be used /// by the rest of the FFI which are independent of @@ -41,40 +40,6 @@ /// assuming that that call completes successfully. /// - In all other cases, 16 shards will be used by default. num_shards: u8, - - /// The maximum number of credential slabs which may be active - /// at any one time. By default, this value will be set to - /// `u32::MAX - 1`, which is the upper-bound on this value. - max_num_credential_slabs: u32, - - /// The maximum number of credential books which may be active - /// at any one time. By default, this value will be set to - /// `u32::MAX - 1`, which is the upper-bound on this value. - max_num_credential_books: u32, - - /// The maximum number of deserialized v0 advertisements - /// which may be active at any one time. By default, this - /// value will be set to `u32::MAX - 1`, which is the upper-bound - /// on this value. - max_num_deserialized_v0_advertisements: u32, - - /// The maximum number of deserialized v1 advertisements - /// which may be active at any one time. By default, this - /// value will be set to `u32::MAX - 1`, which is the upper-bound - /// on this value. - max_num_deserialized_v1_advertisements: u32, - - /// The maximum number of v0 advertisement builders - /// which may be active at any one time. By default, this - /// value will be set to `u32::MAX - 1`, which is the upper-bound - /// on this value. - max_num_v0_advertisement_builders: u32, - - /// The maximum number of v1 advertisement builders - /// which may be active at any one time. By default, this - /// value will be set to `u32::MAX - 1`, which is the upper-bound - /// on this value. - max_num_v1_advertisement_builders: u32, } impl Default for CommonConfig { @@ -85,15 +50,7 @@ impl CommonConfig { pub(crate) const fn new() -> Self { - Self { - num_shards: 0, - max_num_credential_slabs: DEFAULT_MAX_HANDLES, - max_num_credential_books: DEFAULT_MAX_HANDLES, - max_num_deserialized_v0_advertisements: DEFAULT_MAX_HANDLES, - max_num_deserialized_v1_advertisements: DEFAULT_MAX_HANDLES, - max_num_v0_advertisement_builders: DEFAULT_MAX_HANDLES, - max_num_v1_advertisement_builders: DEFAULT_MAX_HANDLES, - } + Self { num_shards: 0 } } #[cfg(feature = "std")] pub(crate) fn num_shards(&self) -> u8 { @@ -114,108 +71,23 @@ self.num_shards } } - pub(crate) fn max_num_credential_slabs(&self) -> u32 { - self.max_num_credential_slabs - } - pub(crate) fn max_num_credential_books(&self) -> u32 { - self.max_num_credential_books - } - pub(crate) fn max_num_deserialized_v0_advertisements(&self) -> u32 { - self.max_num_deserialized_v0_advertisements - } - pub(crate) fn max_num_deserialized_v1_advertisements(&self) -> u32 { - self.max_num_deserialized_v1_advertisements - } - pub(crate) fn max_num_v0_advertisement_builders(&self) -> u32 { - self.max_num_v0_advertisement_builders - } - pub(crate) fn max_num_v1_advertisement_builders(&self) -> u32 { - self.max_num_v1_advertisement_builders - } pub(crate) fn set_num_shards(&mut self, num_shards: u8) { self.num_shards = num_shards } +} - /// Sets the maximum number of active handles to credential-books - /// which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_credential_books(&mut self, max_num_credential_books: u32) { - self.max_num_credential_books = DEFAULT_MAX_HANDLES.min(max_num_credential_books) - } - - /// Sets the maximum number of active handles to credential-slabs - /// which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_credential_slabs(&mut self, max_num_credential_slabs: u32) { - self.max_num_credential_slabs = DEFAULT_MAX_HANDLES.min(max_num_credential_slabs) - } - - /// Sets the maximum number of active handles to deserialized v0 - /// advertisements which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_deserialized_v0_advertisements( - &mut self, - max_num_deserialized_v0_advertisements: u32, - ) { - self.max_num_deserialized_v0_advertisements = - DEFAULT_MAX_HANDLES.min(max_num_deserialized_v0_advertisements) - } - - /// Sets the maximum number of active handles to deserialized v1 - /// advertisements which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_deserialized_v1_advertisements( - &mut self, - max_num_deserialized_v1_advertisements: u32, - ) { - self.max_num_deserialized_v1_advertisements = - DEFAULT_MAX_HANDLES.min(max_num_deserialized_v1_advertisements) - } - /// Sets the maximum number of active handles to v0 advertisement - /// builders which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_v0_advertisement_builders( - &mut self, - max_num_v0_advertisement_builders: u32, - ) { - self.max_num_v0_advertisement_builders = - DEFAULT_MAX_HANDLES.min(max_num_v0_advertisement_builders) - } - /// Sets the maximum number of active handles to v1 advertisement - /// builders which may be active at any one time. - /// Max value: `u32::MAX - 1`. - pub fn set_max_num_v1_advertisement_builders( - &mut self, - max_num_v1_advertisement_builders: u32, - ) { - self.max_num_v1_advertisement_builders = - DEFAULT_MAX_HANDLES.min(max_num_v1_advertisement_builders) +pub(crate) fn default_handle_map_dimensions() -> handle_map::HandleMapDimensions { + handle_map::HandleMapDimensions { + num_shards: global_num_shards(), + max_active_handles: MAX_HANDLES, } } static COMMON_CONFIG: RwLock<CommonConfig> = RwLock::new(CommonConfig::new()); -pub(crate) fn global_num_shards() -> u8 { +fn global_num_shards() -> u8 { COMMON_CONFIG.read().num_shards() } -pub(crate) fn global_max_num_credential_slabs() -> u32 { - COMMON_CONFIG.read().max_num_credential_slabs() -} -pub(crate) fn global_max_num_credential_books() -> u32 { - COMMON_CONFIG.read().max_num_credential_books() -} -pub(crate) fn global_max_num_deserialized_v0_advertisements() -> u32 { - COMMON_CONFIG.read().max_num_deserialized_v0_advertisements() -} -pub(crate) fn global_max_num_deserialized_v1_advertisements() -> u32 { - COMMON_CONFIG.read().max_num_deserialized_v1_advertisements() -} -pub(crate) fn global_max_num_v0_advertisement_builders() -> u32 { - COMMON_CONFIG.read().max_num_v0_advertisement_builders() -} -pub(crate) fn global_max_num_v1_advertisement_builders() -> u32 { - COMMON_CONFIG.read().max_num_v1_advertisement_builders() -} /// Sets an override to the number of shards to employ in the NP FFI's /// internal handle-maps, which places an upper bound on the number @@ -236,94 +108,43 @@ config.set_num_shards(num_shards); } -/// Sets the maximum number of active handles to credential slabs -/// which may be active at any one time. Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential slabs. -pub fn global_config_set_max_num_credential_slabs(max_num_credential_slabs: u32) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_credential_slabs(max_num_credential_slabs); -} -/// Sets the maximum number of active handles to credential books -/// which may be active at any one time. Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call utilizing credential books. -pub fn global_config_set_max_num_credential_books(max_num_credential_books: u32) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_credential_books(max_num_credential_books); +/// Holds the count of handles currently allocated for each handle type +#[repr(C)] +pub struct CurrentHandleAllocations { + cred_book: u32, + cred_slab: u32, + decrypted_metadata: u32, + v0_payload: u32, + legible_v1_sections: u32, + v0_advertisement_builder: u32, + v1_advertisement_builder: u32, } -/// Sets the maximum number of active handles to deserialized v0 -/// advertisements which may be active at any one time. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V0 advertisement. -pub fn global_config_set_max_num_deserialized_v0_advertisements( - max_num_deserialized_v0_advertisements: u32, -) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_deserialized_v0_advertisements(max_num_deserialized_v0_advertisements); +/// Returns the count of currently allocated handle types being held by the rust layer. Useful +/// for debugging, logging, and testing. +pub fn global_config_get_current_allocation_count() -> CurrentHandleAllocations { + CurrentHandleAllocations { + cred_book: crate::credentials::credential_book::get_current_allocation_count(), + cred_slab: crate::credentials::credential_slab::get_current_allocation_count(), + decrypted_metadata: crate::deserialize::decrypted_metadata::get_current_allocation_count(), + v0_payload: crate::deserialize::v0::v0_payload::get_current_allocation_count(), + legible_v1_sections: + crate::deserialize::v1::legible_v1_sections::get_current_allocation_count(), + v0_advertisement_builder: + crate::serialize::v0::advertisement_builder::get_current_allocation_count(), + v1_advertisement_builder: + crate::serialize::v1::advertisement_builder::get_current_allocation_count(), + } } -/// Sets the maximum number of active handles to deserialized v1 -/// advertisements which may be active at any one time. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a deserialized V1 advertisement. -pub fn global_config_set_max_num_deserialized_v1_advertisements( - max_num_deserialized_v1_advertisements: u32, -) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_deserialized_v1_advertisements(max_num_deserialized_v1_advertisements); -} - -/// Sets the maximum number of active handles to v0 advertisement -/// builders which may be active at any one time. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a v0 advertisement builder. -pub fn global_config_set_max_num_v0_advertisement_builders(max_num_v0_advertisement_builders: u32) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_v0_advertisement_builders(max_num_v0_advertisement_builders); -} - -/// Sets the maximum number of active handles to v1 advertisement -/// builders which may be active at any one time. -/// Max value: `u32::MAX - 1`. -/// -/// Setting this value will have no effect if the handle-maps for the -/// API have already begun being used by the client code, and any -/// values set will take effect upon the first usage of any API -/// call which references or returns a v1 advertisement builder. -pub fn global_config_set_max_num_v1_advertisement_builders(max_num_v1_advertisement_builders: u32) { - let mut config = COMMON_CONFIG.write(); - config.set_max_num_v1_advertisement_builders(max_num_v1_advertisement_builders); -} -// API surfaces: - /// A result-type enum which tells the caller whether/not a deallocation /// succeeded or failed due to the requested handle not being present. #[repr(C)] pub enum DeallocateResult { /// The requested handle to deallocate was not present in the map - NotPresent = 0, + NotPresent = 1, /// The object behind the handle was successfully deallocated - Success = 1, + Success = 2, } impl From<Result<(), HandleNotPresentError>> for DeallocateResult { @@ -431,43 +252,6 @@ CRYPTO_RNG.write() } -/// The DE type for an encrypted identity -#[derive(Clone, Copy)] -#[repr(u8)] -pub enum EncryptedIdentityType { - /// Identity for broadcasts to nearby devices with the same - /// logged-in-account (for some account). - Private = 1, - /// Identity for broadcasts to nearby devices which this - /// device has declared to trust. - Trusted = 2, - /// Identity for broadcasts to devices which have been provisioned - /// offline with this device. - Provisioned = 4, -} - -impl From<EncryptedIdentityType> for np_adv::de_type::EncryptedIdentityDataElementType { - fn from(val: EncryptedIdentityType) -> np_adv::de_type::EncryptedIdentityDataElementType { - use np_adv::de_type::EncryptedIdentityDataElementType; - match val { - EncryptedIdentityType::Private => EncryptedIdentityDataElementType::Private, - EncryptedIdentityType::Trusted => EncryptedIdentityDataElementType::Trusted, - EncryptedIdentityType::Provisioned => EncryptedIdentityDataElementType::Provisioned, - } - } -} - -impl From<np_adv::de_type::EncryptedIdentityDataElementType> for EncryptedIdentityType { - fn from(value: np_adv::de_type::EncryptedIdentityDataElementType) -> Self { - use np_adv::de_type::EncryptedIdentityDataElementType; - match value { - EncryptedIdentityDataElementType::Private => Self::Private, - EncryptedIdentityDataElementType::Trusted => Self::Trusted, - EncryptedIdentityDataElementType::Provisioned => Self::Provisioned, - } - } -} - /// Error returned if the bit representation of a supposedly-Rust-constructed /// -and-validated type actually doesn't correspond to the format of the /// data structure expected on the Rust side of the boundary, and performing
diff --git a/nearby/presence/np_ffi_core/src/credentials.rs b/nearby/presence/np_ffi_core/src/credentials.rs index dad61ee..1ad303f 100644 --- a/nearby/presence/np_ffi_core/src/credentials.rs +++ b/nearby/presence/np_ffi_core/src/credentials.rs
@@ -15,33 +15,30 @@ use crate::common::*; use crate::utils::{FfiEnum, LocksLongerThan}; -use crypto_provider::ed25519::InvalidPublicKeyBytes; +use crypto_provider::{ed25519, CryptoProvider}; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{ - declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError, - HandleMapTryAllocateError, -}; +use handle_map::{declare_handle_map, HandleLike, HandleMapFullError, HandleMapTryAllocateError}; +use np_adv::extended; use std::sync::Arc; +type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519; + /// Cryptographic information about a particular V0 discovery credential /// necessary to match and decrypt encrypted V0 advertisements. #[repr(C)] pub struct V0DiscoveryCredential { key_seed: [u8; 32], - legacy_metadata_key_hmac: [u8; 32], + identity_token_hmac: [u8; 32], } impl V0DiscoveryCredential { /// Constructs a new V0 discovery credential with the given 32-byte key-seed /// and the given 32-byte HMAC for the (14-byte) legacy metadata key. - pub fn new(key_seed: [u8; 32], legacy_metadata_key_hmac: [u8; 32]) -> Self { - Self { key_seed, legacy_metadata_key_hmac } + pub fn new(key_seed: [u8; 32], identity_token_hmac: [u8; 32]) -> Self { + Self { key_seed, identity_token_hmac } } fn into_internal(self) -> np_adv::credential::v0::V0DiscoveryCredential { - np_adv::credential::v0::V0DiscoveryCredential::new( - self.key_seed, - self.legacy_metadata_key_hmac, - ) + np_adv::credential::v0::V0DiscoveryCredential::new(self.key_seed, self.identity_token_hmac) } } @@ -50,8 +47,9 @@ #[repr(C)] pub struct V1DiscoveryCredential { key_seed: [u8; 32], - expected_unsigned_metadata_key_hmac: [u8; 32], - expected_signed_metadata_key_hmac: [u8; 32], + expected_mic_short_salt_identity_token_hmac: [u8; 32], + expected_mic_extended_salt_identity_token_hmac: [u8; 32], + expected_signature_identity_token_hmac: [u8; 32], pub_key: [u8; 32], } @@ -61,26 +59,30 @@ /// the metadata key, and the given public key for signature verification. pub fn new( key_seed: [u8; 32], - expected_unsigned_metadata_key_hmac: [u8; 32], - expected_signed_metadata_key_hmac: [u8; 32], + expected_mic_short_salt_identity_token_hmac: [u8; 32], + expected_mic_extended_salt_identity_token_hmac: [u8; 32], + expected_signature_identity_token_hmac: [u8; 32], pub_key: [u8; 32], ) -> Self { Self { key_seed, - expected_unsigned_metadata_key_hmac, - expected_signed_metadata_key_hmac, + expected_mic_short_salt_identity_token_hmac, + expected_mic_extended_salt_identity_token_hmac, + expected_signature_identity_token_hmac, pub_key, } } fn into_internal( self, - ) -> Result<np_adv::credential::v1::V1DiscoveryCredential, InvalidPublicKeyBytes> { - np_adv::credential::v1::V1DiscoveryCredential::new::<CryptoProviderImpl>( + ) -> Result<np_adv::credential::v1::V1DiscoveryCredential, ed25519::InvalidPublicKeyBytes> { + let public_key = ed25519::PublicKey::from_bytes::<Ed25519ProviderImpl>(self.pub_key)?; + Ok(np_adv::credential::v1::V1DiscoveryCredential::new( self.key_seed, - self.expected_unsigned_metadata_key_hmac, - self.expected_signed_metadata_key_hmac, - self.pub_key, - ) + self.expected_mic_short_salt_identity_token_hmac, + self.expected_mic_extended_salt_identity_token_hmac, + self.expected_signature_identity_token_hmac, + public_key, + )) } } @@ -107,8 +109,11 @@ /// (some arbitrary `u32` identifier) and encrypted metadata bytes, /// copied from the given slice. pub fn new(cred_id: u32, encrypted_metadata_bytes: &[u8]) -> Self { - let encrypted_metadata_bytes = encrypted_metadata_bytes.to_vec().into_boxed_slice(); - let encrypted_metadata_bytes = Arc::from(encrypted_metadata_bytes); + Self::from_arc_bytes(cred_id, encrypted_metadata_bytes.to_vec().into()) + } + /// Constructs a new matched credential from the given match-id + /// (some arbitrary `u32` identifier) and encrypted metadata bytes. + pub fn from_arc_bytes(cred_id: u32, encrypted_metadata_bytes: Arc<[u8]>) -> Self { Self { cred_id, encrypted_metadata_bytes } } /// Gets the pre-specified numerical identifier for this matched-credential. @@ -125,7 +130,7 @@ impl Eq for MatchedCredential {} -impl np_adv::credential::MatchedCredential for MatchedCredential { +impl np_adv::credential::matched::MatchedCredential for MatchedCredential { type EncryptedMetadata = Arc<[u8]>; type EncryptedMetadataFetchError = core::convert::Infallible; fn fetch_encrypted_metadata(&self) -> Result<Arc<[u8]>, core::convert::Infallible> { @@ -155,9 +160,10 @@ discovery_credential: V0DiscoveryCredential, match_data: MatchedCredential, ) { - let discovery_credential = discovery_credential.into_internal(); - let matchable_credential = - np_adv::credential::MatchableCredential { discovery_credential, match_data }; + let matchable_credential = np_adv::credential::MatchableCredential { + discovery_credential: discovery_credential.into_internal(), + match_data, + }; self.v0_creds.push(matchable_credential); } /// Adds the given V1 discovery credential with the given @@ -167,10 +173,10 @@ &mut self, discovery_credential: V1DiscoveryCredential, match_data: MatchedCredential, - ) -> Result<(), InvalidPublicKeyBytes> { - discovery_credential.into_internal().map(|discovery_credential| { + ) -> Result<(), ed25519::InvalidPublicKeyBytes> { + discovery_credential.into_internal().map(|dc| { let matchable_credential = - np_adv::credential::MatchableCredential { discovery_credential, match_data }; + np_adv::credential::MatchableCredential { discovery_credential: dc, match_data }; self.v1_creds.push(matchable_credential); }) } @@ -232,23 +238,16 @@ handle_id: u64, } -fn get_credential_slab_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_credential_slabs(), - } -} - declare_handle_map!( credential_slab, - super::get_credential_slab_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::CredentialSlab, super::CredentialSlabInternals ); impl CredentialSlab { - /// Adds the given V0 discovery credential with some associated - /// match-data to this credential slab. + /// Adds the given V0 discovery credential with some associated match-data to this credential + /// slab. This uses the handle but does not transfer ownership of it. pub fn add_v0( &self, discovery_credential: V0DiscoveryCredential, @@ -262,8 +261,8 @@ Err(_) => AddV0CredentialToSlabResult::InvalidHandle, } } - /// Adds the given V1 discovery credential with some associated - /// match-data to this credential slab. + /// Adds the given V1 discovery credential with some associated match-data to this credential + /// slab. This uses the handle but does not transfer ownership of it. pub fn add_v1( &self, discovery_credential: V1DiscoveryCredential, @@ -279,7 +278,8 @@ } } -/// Allocates a new credential-slab, returning a handle to the created object +/// Allocates a new credential-slab, returning a handle to the created object. The caller is given +/// ownership of the created handle. pub fn create_credential_slab() -> CreateCredentialSlabResult { CredentialSlab::allocate(CredentialSlabInternals::new).into() } @@ -313,13 +313,6 @@ } } -fn get_credential_book_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_credential_books(), - } -} - /// A `#[repr(C)]` handle to a value of type `CredentialBookInternals` #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq)] @@ -329,7 +322,7 @@ declare_handle_map!( credential_book, - super::get_credential_book_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::CredentialBook, super::CredentialBookInternals ); @@ -359,7 +352,10 @@ impl LocksLongerThan<CredentialSlab> for CredentialBook {} -/// Allocates a new credential-book, returning a handle to the created object +/// Allocates a new credential-book, returning a handle to the created object. This takes ownership +/// of the `credential_slab` handle except in the case where `NoSpaceLeft` is the error returned. +/// In that case the caller will retain ownership of the slab handle. The caller is given ownership +/// of the returned credential book handle if present. pub fn create_credential_book_from_slab( credential_slab: CredentialSlab, ) -> CreateCredentialBookResult { @@ -399,12 +395,14 @@ declare_enum_cast! {into_success, Success, CredentialBook} } -/// Deallocates a credential-book by its handle +/// Deallocates a credential-book by its handle. This takes ownership of the credential book +/// handle. pub fn deallocate_credential_book(credential_book: CredentialBook) -> DeallocateResult { credential_book.deallocate().map(|_| ()).into() } -/// Deallocates a credential-slab by its handle +/// Deallocates a credential-slab by its handle. This takes ownership of the credential slab +/// handle. pub fn deallocate_credential_slab(credential_slab: CredentialSlab) -> DeallocateResult { credential_slab.deallocate().map(|_| ()).into() } @@ -414,7 +412,7 @@ #[repr(C)] pub struct V0BroadcastCredential { key_seed: [u8; 32], - metadata_key: [u8; 14], + identity_token: [u8; 14], } impl V0BroadcastCredential { @@ -425,15 +423,13 @@ /// of the raw bytes of sensitive cryptographic info over FFI, /// foreign-lang code around how this information is maintained /// deserves close scrutiny. - pub fn new(key_seed: [u8; 32], metadata_key: [u8; 14]) -> Self { - Self { key_seed, metadata_key } + pub fn new(key_seed: [u8; 32], identity_token: ldt_np_adv::V0IdentityToken) -> Self { + Self { key_seed, identity_token: identity_token.bytes() } } - pub(crate) fn into_internal( - self, - ) -> np_adv::credential::SimpleBroadcastCryptoMaterial<np_adv::credential::v0::V0> { - np_adv::credential::SimpleBroadcastCryptoMaterial::new( + pub(crate) fn into_internal(self) -> np_adv::credential::v0::V0BroadcastCredential { + np_adv::credential::v0::V0BroadcastCredential::new( self.key_seed, - np_adv::legacy::ShortMetadataKey(self.metadata_key), + self.identity_token.into(), ) } } @@ -443,7 +439,7 @@ #[repr(C)] pub struct V1BroadcastCredential { key_seed: [u8; 32], - metadata_key: [u8; 16], + identity_token: [u8; 16], private_key: [u8; 32], } @@ -457,16 +453,18 @@ /// sensitive cryptographic info) over FFI, foreign-lang /// code around how this information is maintained /// deserves close scrutiny. - pub const fn new(key_seed: [u8; 32], metadata_key: [u8; 16], private_key: [u8; 32]) -> Self { - Self { key_seed, metadata_key, private_key } + pub const fn new( + key_seed: [u8; 32], + identity_token: extended::V1IdentityToken, + private_key: [u8; 32], + ) -> Self { + Self { key_seed, identity_token: identity_token.into_bytes(), private_key } } - pub(crate) fn into_internal( - self, - ) -> np_adv::credential::v1::SimpleSignedBroadcastCryptoMaterial { + pub(crate) fn into_internal(self) -> np_adv::credential::v1::V1BroadcastCredential { let permit = crypto_provider::ed25519::RawPrivateKeyPermit::default(); - np_adv::credential::v1::SimpleSignedBroadcastCryptoMaterial::new( + np_adv::credential::v1::V1BroadcastCredential::new( self.key_seed, - np_adv::MetadataKey(self.metadata_key), + self.identity_token.into(), crypto_provider::ed25519::PrivateKey::from_raw_private_key(self.private_key, &permit), ) }
diff --git a/nearby/presence/np_ffi_core/src/deserialize.rs b/nearby/presence/np_ffi_core/src/deserialize.rs index 09df8a4..dffa8d1 100644 --- a/nearby/presence/np_ffi_core/src/deserialize.rs +++ b/nearby/presence/np_ffi_core/src/deserialize.rs
@@ -19,9 +19,7 @@ use crate::deserialize::v1::*; use crate::utils::FfiEnum; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{ - declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError, HandleNotPresentError, -}; +use handle_map::{declare_handle_map, HandleLike, HandleMapFullError, HandleNotPresentError}; use np_adv::deserialization_arena; pub mod v0; @@ -73,7 +71,8 @@ declare_enum_cast! {into_v0, V0, DeserializedV0Advertisement} declare_enum_cast! {into_v1, V1, DeserializedV1Advertisement} - /// Deallocates any internal data referenced by a `DeserializeAdvertisementResult` + /// Deallocates any internal data referenced by a `DeserializeAdvertisementResult`. This takes + /// ownership of any internal handles. pub fn deallocate(self) -> DeallocateResult { match self { DeserializeAdvertisementResult::Error => DeallocateResult::Success, @@ -133,8 +132,9 @@ } } -/// Attempts to deserialize an advertisement with the given payload. -/// Suitable for langs which have a suitably expressive slice-type. +/// Attempts to deserialize an advertisement with the given payload. Suitable for langs which have +/// a suitably expressive slice-type. This uses the given `credential_book` handle but does not +/// take ownership of it. The caller is given ownership of any handles in the returned structure. pub fn deserialize_advertisement_from_slice( adv_payload: &[u8], credential_book: CredentialBook, @@ -147,8 +147,10 @@ } } -/// Attempts to deserialize an advertisement with the given payload. -/// Suitable for langs which don't have an expressive-enough slice type. +/// Attempts to deserialize an advertisement with the given payload. Suitable for langs which +/// don't have an expressive-enough slice type. This uses the given `credential_book` handle but +/// does not take ownership of it. The caller is given ownership of any handles in the returned +/// structure. pub fn deserialize_advertisement( adv_payload: &RawAdvertisementPayload, credential_book: CredentialBook, @@ -215,15 +217,11 @@ declare_handle_map!( decrypted_metadata, - super::get_decrypted_metadata_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::DecryptedMetadata, super::DecryptedMetadataInternals ); -fn get_decrypted_metadata_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { num_shards: global_num_shards(), max_active_handles: DEFAULT_MAX_HANDLES } -} - /// The pointer and length of the decrypted metadata byte buffer #[repr(C)] pub struct MetadataBufferParts { @@ -271,7 +269,8 @@ } impl DecryptedMetadata { - /// Gets the raw parts, pointer + length representation of the metadata byte buffer + /// Gets the raw parts, pointer + length representation of the metadata byte buffer. This uses + /// the handle but does not take ownership of it. pub fn get_metadata_buffer_parts(&self) -> GetMetadataBufferPartsResult { match self.get() { Ok(metadata_internals) => { @@ -285,8 +284,8 @@ } } - /// Frees the underlying decrypted metadata buffer - pub fn deallocate_metadata(&self) -> DeallocateResult { + /// Frees the underlying decrypted metadata buffer. This takes ownership of the handle. + pub fn deallocate_metadata(self) -> DeallocateResult { self.deallocate().map(|_| ()).into() } }
diff --git a/nearby/presence/np_ffi_core/src/deserialize/v0.rs b/nearby/presence/np_ffi_core/src/deserialize/v0.rs index c4f117f..79528a0 100644 --- a/nearby/presence/np_ffi_core/src/deserialize/v0.rs +++ b/nearby/presence/np_ffi_core/src/deserialize/v0.rs
@@ -22,9 +22,9 @@ use crate::utils::{FfiEnum, LocksLongerThan}; use crate::v0::V0DataElement; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError}; -use np_adv::HasIdentityMatch; -use std::vec::Vec; +use handle_map::{declare_handle_map, HandleLike, HandleMapFullError}; +use np_adv::credential::matched::HasIdentityMatch; +use np_adv::legacy; /// Discriminant for possible results of V0 advertisement deserialization #[derive(Clone, Copy)] @@ -33,12 +33,12 @@ /// The deserialized V0 advertisement was legible. /// The associated payload may be obtained via /// `DeserializedV0Advertisement#into_legible`. - Legible = 0, + Legible = 1, /// The deserialized V0 advertisement is illegible, /// likely meaning that the receiver does not hold /// the proper credentials to be able to read /// the received advertisement. - NoMatchingCredentials = 1, + NoMatchingCredentials = 2, } /// Represents a deserialized V0 advertisement @@ -62,8 +62,9 @@ } impl DeserializedV0Advertisement { - /// Attempts to deallocate memory utilized internally by this V0 advertisement - /// (which contains a handle to actual advertisement contents behind-the-scenes). + /// Attempts to deallocate memory utilized internally by this V0 advertisement (which contains + /// a handle to actual advertisement contents behind-the-scenes). This function takes ownership + /// of that internal handle. pub fn deallocate(self) -> DeallocateResult { match self { DeserializedV0Advertisement::Legible(adv) => adv.deallocate(), @@ -72,25 +73,25 @@ } pub(crate) fn allocate_with_contents( - contents: np_adv::V0AdvertisementContents< - np_adv::credential::ReferencedMatchedCredential<MatchedCredential>, + contents: legacy::V0AdvertisementContents< + np_adv::credential::matched::ReferencedMatchedCredential<MatchedCredential>, >, ) -> Result<Self, DeserializeAdvertisementError> { match contents { - np_adv::V0AdvertisementContents::Plaintext(plaintext_contents) => { + legacy::V0AdvertisementContents::Plaintext(plaintext_contents) => { let adv = LegibleDeserializedV0Advertisement::allocate_with_plaintext_contents( plaintext_contents, )?; Ok(Self::Legible(adv)) } - np_adv::V0AdvertisementContents::Decrypted(decrypted_contents) => { + legacy::V0AdvertisementContents::Decrypted(decrypted_contents) => { let decrypted_contents = decrypted_contents.clone_match_data(); let adv = LegibleDeserializedV0Advertisement::allocate_with_decrypted_contents( decrypted_contents, )?; Ok(Self::Legible(adv)) } - np_adv::V0AdvertisementContents::NoMatchingCredentials => { + legacy::V0AdvertisementContents::NoMatchingCredentials => { Ok(Self::NoMatchingCredentials) } } @@ -109,7 +110,7 @@ impl LegibleDeserializedV0Advertisement { pub(crate) fn allocate_with_plaintext_contents( - contents: np_adv::legacy::deserialize::PlaintextAdvContents, + contents: legacy::deserialize::UnencryptedAdvContents, ) -> Result<Self, DeserializeAdvertisementError> { let data_elements = contents .data_elements() @@ -120,9 +121,9 @@ Ok(Self { num_des, payload, identity_kind: DeserializedV0IdentityKind::Plaintext }) } pub(crate) fn allocate_with_decrypted_contents( - contents: np_adv::WithMatchedCredential< + contents: np_adv::credential::matched::WithMatchedCredential< MatchedCredential, - np_adv::legacy::deserialize::DecryptedAdvContents, + legacy::deserialize::DecryptedAdvContents, >, ) -> Result<Self, DeserializeAdvertisementError> { let data_elements = contents @@ -133,28 +134,23 @@ let num_des = data_elements.len() as u8; let salt = contents.contents().salt(); - let identity_type = contents.contents().identity_type(); // Reduce the information contained in the contents to just // the metadata key, since we're done copying over the DEs // and other data into an FFI-friendly form. - let match_data = contents.map(|x| x.metadata_key()); + let match_data = contents.map(|x| x.identity_token()); - let payload = V0Payload::allocate_with_decrypted_contents( - identity_type, - salt, - match_data, - data_elements, - )?; + let payload = V0Payload::allocate_with_decrypted_contents(salt, match_data, data_elements)?; Ok(Self { num_des, payload, identity_kind: DeserializedV0IdentityKind::Decrypted }) } - /// Gets the number of data-elements in this adv's payload - /// Suitable as an iteration bound for `Self.into_payload().get_de(...)`. + /// Gets the number of data-elements in this adv's payload. This number is suitable as an + /// iteration bound for `Self.into_payload().get_de(...)`. pub fn num_des(&self) -> u8 { self.num_des } - /// Destructures this legible advertisement into just the payload + /// Get a copy of the payload handle. This does not copy the underlying payload. The copied + /// handle shares a lifetime with the payload handle in this struct; it's the same handle. pub fn payload(&self) -> V0Payload { self.payload } @@ -163,7 +159,8 @@ pub fn identity_kind(&self) -> DeserializedV0IdentityKind { self.identity_kind } - /// Deallocates the underlying handle of the payload + /// Deallocates the underlying handle of the payload. This function takes ownership of the + /// payload handle. pub fn deallocate(self) -> DeallocateResult { self.payload.deallocate().map(|_| ()).into() } @@ -175,9 +172,9 @@ #[repr(u8)] pub enum DeserializedV0IdentityKind { /// The deserialized identity was a plaintext identity. - Plaintext = 0, + Plaintext = 1, /// The deserialized identity was some decrypted identity. - Decrypted = 1, + Decrypted = 2, } /// Information about the identity which matched a @@ -185,13 +182,11 @@ #[derive(Clone, Copy)] #[repr(C)] pub struct DeserializedV0IdentityDetails { - /// The identity type (private/provisioned/trusted) - identity_type: EncryptedIdentityType, /// The ID of the credential which /// matched the deserialized adv cred_id: u32, - /// The 14-byte legacy metadata key - metadata_key: [u8; 14], + /// The 14-byte legacy identity token + identity_token: [u8; 14], /// The 2-byte advertisement salt salt: [u8; 2], } @@ -199,27 +194,19 @@ impl DeserializedV0IdentityDetails { pub(crate) fn new( cred_id: u32, - identity_type: np_adv::de_type::EncryptedIdentityDataElementType, - salt: ldt_np_adv::LegacySalt, - metadata_key: np_adv::legacy::ShortMetadataKey, + salt: ldt_np_adv::V0Salt, + identity_token: ldt_np_adv::V0IdentityToken, ) -> Self { - let metadata_key = metadata_key.0; - let salt = *salt.bytes(); - let identity_type = identity_type.into(); - Self { identity_type, cred_id, salt, metadata_key } + let salt = salt.bytes(); + Self { cred_id, salt, identity_token: identity_token.bytes() } } - /// Returns the ID of the credential which - /// matched the deserialized adv + /// Returns the ID of the credential which matched the deserialized adv pub fn cred_id(&self) -> u32 { self.cred_id } - /// Returns the identity type (private/provisioned/trusted) - pub fn identity_type(&self) -> EncryptedIdentityType { - self.identity_type - } /// Returns the 14-byte legacy metadata key - pub fn metadata_key(&self) -> [u8; 14] { - self.metadata_key + pub fn identity_token(&self) -> [u8; 14] { + self.identity_token } /// Returns the 2-byte advertisement salt pub fn salt(&self) -> [u8; 2] { @@ -275,22 +262,23 @@ /// The metadata key, together with the matched /// credential and enough information to decrypt /// the credential metadata, if desired. - match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::legacy::ShortMetadataKey>, + match_data: np_adv::credential::matched::WithMatchedCredential< + MatchedCredential, + ldt_np_adv::V0IdentityToken, + >, } impl DeserializedV0IdentityInternals { pub(crate) fn new( - identity_type: np_adv::de_type::EncryptedIdentityDataElementType, - salt: ldt_np_adv::LegacySalt, - match_data: np_adv::WithMatchedCredential< + salt: ldt_np_adv::V0Salt, + match_data: np_adv::credential::matched::WithMatchedCredential< MatchedCredential, - np_adv::legacy::ShortMetadataKey, + ldt_np_adv::V0IdentityToken, >, ) -> Self { let cred_id = match_data.matched_credential().id(); - let metadata_key = match_data.contents(); - let details = - DeserializedV0IdentityDetails::new(cred_id, identity_type, salt, *metadata_key); + let identity_token = match_data.contents(); + let details = DeserializedV0IdentityDetails::new(cred_id, salt, *identity_token); Self { details, match_data } } /// Gets the directly-transmissible details about @@ -342,13 +330,6 @@ } } -fn get_v0_payload_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_deserialized_v0_advertisements(), - } -} - /// A `#[repr(C)]` handle to a value of type `V0PayloadInternals` #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq)] @@ -358,7 +339,7 @@ declare_handle_map!( v0_payload, - super::get_v0_payload_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::V0Payload, super::V0PayloadInternals ); @@ -369,9 +350,7 @@ impl V0Payload { pub(crate) fn allocate_with_plaintext_data_elements( - data_elements: Vec< - np_adv::legacy::deserialize::PlainDataElement<np_adv::legacy::Plaintext>, - >, + data_elements: Vec<legacy::deserialize::DeserializedDataElement<legacy::Plaintext>>, ) -> Result<Self, HandleMapFullError> { Self::allocate(move || { let des = data_elements.into_iter().map(V0DataElement::from).collect(); @@ -380,24 +359,21 @@ }) } pub(crate) fn allocate_with_decrypted_contents( - identity_type: np_adv::de_type::EncryptedIdentityDataElementType, - salt: ldt_np_adv::LegacySalt, - match_data: np_adv::WithMatchedCredential< + salt: ldt_np_adv::V0Salt, + match_data: np_adv::credential::matched::WithMatchedCredential< MatchedCredential, - np_adv::legacy::ShortMetadataKey, + ldt_np_adv::V0IdentityToken, >, - data_elements: Vec< - np_adv::legacy::deserialize::PlainDataElement<np_adv::legacy::Ciphertext>, - >, + data_elements: Vec<legacy::deserialize::DeserializedDataElement<legacy::Ciphertext>>, ) -> Result<Self, HandleMapFullError> { Self::allocate(move || { let des = data_elements.into_iter().map(V0DataElement::from).collect(); - let identity = - Some(DeserializedV0IdentityInternals::new(identity_type, salt, match_data)); + let identity = Some(DeserializedV0IdentityInternals::new(salt, match_data)); V0PayloadInternals { des, identity } }) } - /// Gets the data-element with the given index in this v0 adv payload + /// Gets the data-element with the given index in this v0 adv payload. This uses the handle but + /// does not take ownership of it. pub fn get_de(&self, index: u8) -> GetV0DEResult { match self.get() { Ok(read_guard) => read_guard.get_de(index), @@ -405,9 +381,9 @@ } } - /// Gets the identity details for this V0 payload, - /// if this payload was associated with an identity - /// (i.e: non-public advertisements). + /// Gets the identity details for this V0 payload, if this payload was associated with an + /// identity (i.e: encrypted advertisements). This uses the handle but does not take ownership + /// of it. pub fn get_identity_details(&self) -> GetV0IdentityDetailsResult { match self.get() { Ok(read_guard) => read_guard.get_identity_details(), @@ -415,8 +391,9 @@ } } - /// Attempts to decrypt the metadata for the matched - /// credential for this V0 payload (if any) + /// Attempts to decrypt the metadata for the matched credential for this V0 payload (if any). + /// This uses the handle but does not take ownership of it. The caller is given ownership of + /// the returned `DecryptedMetadata` handle if present. pub fn decrypt_metadata(&self) -> DecryptMetadataResult { match self.get() { Ok(read_guard) => match read_guard.decrypt_metadata() { @@ -427,7 +404,7 @@ } } - /// Deallocates any underlying data held by a V0Payload + /// Deallocates any underlying data held by a `V0Payload`. This takes ownership of the handle. pub fn deallocate_payload(&self) -> DeallocateResult { self.deallocate().map(|_| ()).into() }
diff --git a/nearby/presence/np_ffi_core/src/deserialize/v1.rs b/nearby/presence/np_ffi_core/src/deserialize/v1.rs index 3bc056d..af54fec 100644 --- a/nearby/presence/np_ffi_core/src/deserialize/v1.rs +++ b/nearby/presence/np_ffi_core/src/deserialize/v1.rs
@@ -14,25 +14,36 @@ //! Core NP Rust FFI structures and methods for v1 advertisement deserialization. use super::DeserializeAdvertisementError; -use crate::common::*; -use crate::credentials::CredentialBook; -use crate::credentials::MatchedCredential; -use crate::deserialize::{allocate_decrypted_metadata_handle, DecryptMetadataResult}; -use crate::utils::*; -use crate::v1::V1VerificationMode; +use crate::{ + common::*, + credentials::{CredentialBook, MatchedCredential}, + deserialize::{allocate_decrypted_metadata_handle, DecryptMetadataResult}, + utils::*, + v1::V1VerificationMode, +}; use array_view::ArrayView; +use crypto_provider::CryptoProvider; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions}; -use np_adv::extended::deserialize::DataElementParseError; -use np_adv::HasIdentityMatch; -use std::vec::Vec; +use handle_map::{declare_handle_map, HandleLike}; +use np_adv::{ + credential::matched::WithMatchedCredential, + extended::{ + deserialize::{ + data_element::DataElementParseError, V1AdvertisementContents, V1DeserializedSection, + }, + salt::MultiSalt, + }, +}; /// Representation of a deserialized V1 advertisement #[repr(C)] pub struct DeserializedV1Advertisement { - num_legible_sections: u8, - num_undecryptable_sections: u8, - legible_sections: LegibleV1Sections, + /// The number of legible sections + pub num_legible_sections: u8, + /// The number of sections that were unable to be decrypted + pub num_undecryptable_sections: u8, + /// A handle to the set of legible (plain or decrypted) sections + pub legible_sections: LegibleV1Sections, } impl DeserializedV1Advertisement { @@ -46,8 +57,9 @@ self.num_undecryptable_sections } - /// Gets the legible section with the given index - /// (which is bounded in `0..self.num_legible_sections()`) + /// Gets the legible section with the given index (which is bounded in + /// `0..self.num_legible_sections()`). This uses the internal handle but does not take + /// ownership of it. pub fn get_section(&self, legible_section_index: u8) -> GetV1SectionResult { match self.legible_sections.get() { Ok(sections_read_guard) => { @@ -57,15 +69,16 @@ } } - /// Attempts to deallocate memory utilized internally by this V1 advertisement - /// (which contains a handle to actual advertisement contents behind-the-scenes). + /// Attempts to deallocate memory utilized internally by this V1 advertisement (which contains + /// a handle to actual advertisement contents behind-the-scenes). This function takes ownership + /// of the internal handle. pub fn deallocate(self) -> DeallocateResult { self.legible_sections.deallocate().map(|_| ()).into() } pub(crate) fn allocate_with_contents( - contents: np_adv::V1AdvertisementContents< - np_adv::credential::ReferencedMatchedCredential<MatchedCredential>, + contents: V1AdvertisementContents< + np_adv::credential::matched::ReferencedMatchedCredential<MatchedCredential>, >, ) -> Result<Self, DeserializeAdvertisementError> { // 16-section limit enforced by np_adv @@ -118,9 +131,9 @@ impl<'adv> TryFrom< Vec< - np_adv::V1DeserializedSection< + V1DeserializedSection< 'adv, - np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>, + np_adv::credential::matched::ReferencedMatchedCredential<'adv, MatchedCredential>, >, >, > for LegibleV1SectionsInternals @@ -129,9 +142,9 @@ fn try_from( contents: Vec< - np_adv::V1DeserializedSection< + V1DeserializedSection< 'adv, - np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>, + np_adv::credential::matched::ReferencedMatchedCredential<'adv, MatchedCredential>, >, >, ) -> Result<Self, Self::Error> { @@ -143,23 +156,16 @@ } } -fn get_legible_v1_sections_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_deserialized_v1_advertisements(), - } -} - /// A `#[repr(C)]` handle to a value of type `LegibleV1SectionsInternals` #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq)] -struct LegibleV1Sections { +pub struct LegibleV1Sections { handle_id: u64, } declare_handle_map!( legible_v1_sections, - super::get_legible_v1_sections_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::LegibleV1Sections, super::LegibleV1SectionsInternals ); @@ -169,8 +175,8 @@ impl LegibleV1Sections { pub(crate) fn allocate_with_contents( contents: Vec< - np_adv::V1DeserializedSection< - np_adv::credential::ReferencedMatchedCredential<MatchedCredential>, + V1DeserializedSection< + np_adv::credential::matched::ReferencedMatchedCredential<MatchedCredential>, >, >, ) -> Result<Self, DeserializeAdvertisementError> { @@ -178,6 +184,31 @@ .map_err(|_| DeserializeAdvertisementError)?; Self::allocate(move || section).map_err(|e| e.into()) } + + /// Gets the legible section with the given index (which is bounded in + /// `0..self.num_legible_sections()`). This function uses this handle but does not take + /// ownership of it. + pub fn get_section(&self, legible_section_index: u8) -> GetV1SectionResult { + match self.get() { + Ok(sections_read_guard) => { + sections_read_guard.get_section(*self, legible_section_index) + } + Err(_) => GetV1SectionResult::Error, + } + } + + /// Get a data element by section index and de index. Similar to `get_section().get_de()` but + /// will only lock the HandleMap once. This function uses this handle but does not take + /// ownership of it. + pub fn get_section_de(&self, legible_section_index: u8, de_index: u8) -> GetV1DEResult { + let Ok(sections) = self.get() else { + return GetV1DEResult::Error; + }; + let Some(section) = sections.get_section_internals(legible_section_index) else { + return GetV1DEResult::Error; + }; + section.get_de(de_index) + } } /// Discriminant for `GetV1SectionResult` @@ -313,31 +344,33 @@ /// passed offset is 255 (causes overflow) or if the section /// is leveraging a public identity, and hence, doesn't have /// an associated salt. - pub(crate) fn derive_16_byte_salt_for_offset(&self, de_offset: u8) -> GetV1DE16ByteSaltResult { + pub(crate) fn derive_16_byte_salt_for_offset<C: CryptoProvider>( + &self, + de_offset: u8, + ) -> GetV1DE16ByteSaltResult { self.identity .as_ref() - .and_then(|x| x.derive_16_byte_salt_for_offset(de_offset)) + .and_then(|x| x.derive_16_byte_salt_for_offset::<C>(de_offset)) .map_or(GetV1DE16ByteSaltResult::Error, GetV1DE16ByteSaltResult::Success) } } impl<'adv> TryFrom< - np_adv::V1DeserializedSection< + V1DeserializedSection< 'adv, - np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>, + np_adv::credential::matched::ReferencedMatchedCredential<'adv, MatchedCredential>, >, > for DeserializedV1SectionInternals { type Error = DataElementParseError; fn try_from( - section: np_adv::V1DeserializedSection< - np_adv::credential::ReferencedMatchedCredential<'adv, MatchedCredential>, + section: V1DeserializedSection< + np_adv::credential::matched::ReferencedMatchedCredential<'adv, MatchedCredential>, >, ) -> Result<Self, Self::Error> { use np_adv::extended::deserialize::Section; - use np_adv::V1DeserializedSection; match section { V1DeserializedSection::Plaintext(section) => { let des = section @@ -354,19 +387,14 @@ .map(|r| r.map(|de| V1DataElement::from(&de))) .collect::<Result<Vec<_>, _>>()?; - let identity_type = section.identity_type(); let verification_mode = section.verification_mode(); - let salt = section.salt(); + let salt = *section.salt(); let match_data = with_matched.clone_match_data(); - let match_data = match_data.map(|x| x.metadata_key()); + let match_data = match_data.map(|x| *x.identity_token()); - let identity = Some(DeserializedV1IdentityInternals::new( - identity_type, - verification_mode, - salt, - match_data, - )); + let identity = + Some(DeserializedV1IdentityInternals::new(verification_mode, salt, match_data)); Ok(Self { des, identity }) } } @@ -392,26 +420,21 @@ /// The metadata key, together with the matched /// credential and enough information to decrypt /// the credential metadata, if desired. - match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::MetadataKey>, + match_data: WithMatchedCredential<MatchedCredential, np_adv::extended::V1IdentityToken>, /// The 16-byte section salt - salt: np_adv::extended::deserialize::RawV1Salt, + salt: MultiSalt, } impl DeserializedV1IdentityInternals { pub(crate) fn new( - identity_type: np_adv::de_type::EncryptedIdentityDataElementType, verification_mode: np_adv::extended::deserialize::VerificationMode, - salt: np_adv::extended::deserialize::RawV1Salt, - match_data: np_adv::WithMatchedCredential<MatchedCredential, np_adv::MetadataKey>, + salt: MultiSalt, + match_data: WithMatchedCredential<MatchedCredential, np_adv::extended::V1IdentityToken>, ) -> Self { let cred_id = match_data.matched_credential().id(); - let metadata_key = match_data.contents(); - let details = DeserializedV1IdentityDetails::new( - cred_id, - identity_type, - verification_mode, - *metadata_key, - ); + let identity_token = match_data.contents(); + let details = + DeserializedV1IdentityDetails::new(cred_id, verification_mode, *identity_token); Self { details, match_data, salt } } /// Gets the directly-transmissible details about @@ -427,13 +450,18 @@ } /// For a given data-element offset, derives a 16-byte DE salt /// for a DE in that position within this section. - pub(crate) fn derive_16_byte_salt_for_offset( + pub(crate) fn derive_16_byte_salt_for_offset<C: CryptoProvider>( &self, de_offset: u8, ) -> Option<FixedSizeArray<16>> { - let section_salt = np_hkdf::v1_salt::V1Salt::<CryptoProviderImpl>::from(self.salt); let de_offset = np_hkdf::v1_salt::DataElementOffset::from(de_offset); - section_salt.derive::<16>(Some(de_offset)).map(FixedSizeArray::from_array) + + match self.salt { + MultiSalt::Short(_) => None, + MultiSalt::Extended(s) => { + s.derive::<16, C>(Some(de_offset)).map(FixedSizeArray::from_array) + } + } } } @@ -482,8 +510,6 @@ #[derive(Clone, Copy)] #[repr(C)] pub struct DeserializedV1IdentityDetails { - /// The identity type (private/provisioned/trusted) - identity_type: EncryptedIdentityType, /// The verification mode (MIC/Signature) which /// was used to verify the decrypted adv contents. verification_mode: V1VerificationMode, @@ -491,38 +517,29 @@ /// matched the deserialized section. cred_id: u32, /// The 16-byte metadata key. - metadata_key: [u8; 16], + identity_token: [u8; 16], } impl DeserializedV1IdentityDetails { pub(crate) fn new( cred_id: u32, - identity_type: np_adv::de_type::EncryptedIdentityDataElementType, verification_mode: np_adv::extended::deserialize::VerificationMode, - metadata_key: np_adv::MetadataKey, + identity_token: np_adv::extended::V1IdentityToken, ) -> Self { - let metadata_key = metadata_key.0; - let identity_type = identity_type.into(); let verification_mode = verification_mode.into(); - Self { cred_id, identity_type, verification_mode, metadata_key } + Self { cred_id, verification_mode, identity_token: identity_token.into_bytes() } } - /// Returns the ID of the credential which - /// matched the deserialized section. + /// Returns the ID of the credential which matched the deserialized section. pub fn cred_id(&self) -> u32 { self.cred_id } - /// Returns the identity type (private/provisioned/trusted) - pub fn identity_type(&self) -> EncryptedIdentityType { - self.identity_type - } - /// Returns the verification mode (MIC/Signature) - /// employed for the decrypted section. + /// Returns the verification mode (MIC/Signature) employed for the decrypted section. pub fn verification_mode(&self) -> V1VerificationMode { self.verification_mode } - /// Returns the 16-byte section metadata key. - pub fn metadata_key(&self) -> [u8; 16] { - self.metadata_key + /// Returns the 16-byte section identity token. + pub fn identity_token(&self) -> [u8; 16] { + self.identity_token } } @@ -554,33 +571,31 @@ GetV1DEResult::Error, ) } - /// Attempts to get the details of the identity employed - /// for the section referenced by this handle. May fail - /// if the handle is invalid, or if the advertisement - /// section leverages a public identity. + /// Attempts to get the details of the identity employed for the section referenced by this + /// handle. May fail if the handle is invalid, or if the advertisement section leverages a + /// public identity. This function does not take ownership of the handle. pub fn get_identity_details(&self) -> GetV1IdentityDetailsResult { self.apply_to_section_internals( DeserializedV1SectionInternals::get_identity_details, GetV1IdentityDetailsResult::Error, ) } - /// Attempts to decrypt the metadata for the matched - /// credential for the V1 section referenced by - /// this handle (if any). + /// Attempts to decrypt the metadata for the matched credential for the V1 section referenced + /// by this handle (if any). This uses but does not take ownership of the handle. pub fn decrypt_metadata(&self) -> DecryptMetadataResult { self.apply_to_section_internals( DeserializedV1SectionInternals::decrypt_metadata, DecryptMetadataResult::Error, ) } - /// Attempts to derive a 16-byte DE salt for a DE in this section - /// with the given DE offset. This operation may fail if the - /// passed offset is 255 (causes overflow) or if the section - /// is leveraging a public identity, and hence, doesn't have - /// an associated salt. + /// Attempts to derive a 16-byte DE salt for a DE in this section with the given DE offset. + /// This operation may fail if the passed offset is 255 (causes overflow) or if the section is + /// leveraging a public identity, and hence, doesn't have an associated salt. pub fn derive_16_byte_salt_for_offset(&self, de_offset: u8) -> GetV1DE16ByteSaltResult { self.apply_to_section_internals( - move |section_ref| section_ref.derive_16_byte_salt_for_offset(de_offset), + move |section_ref| { + section_ref.derive_16_byte_salt_for_offset::<CryptoProviderImpl>(de_offset) + }, GetV1DE16ByteSaltResult::Error, ) } @@ -661,8 +676,8 @@ } } -impl<'a> From<&'a np_adv::extended::deserialize::DataElement<'a>> for V1DataElement { - fn from(de: &'a np_adv::extended::deserialize::DataElement<'a>) -> Self { +impl<'a> From<&'a np_adv::extended::deserialize::data_element::DataElement<'a>> for V1DataElement { + fn from(de: &'a np_adv::extended::deserialize::data_element::DataElement<'a>) -> Self { let offset = de.offset().as_u8(); let de_type = V1DEType::from(de.de_type()); let contents_as_slice = de.contents(); @@ -698,8 +713,7 @@ pub fn de_type(&self) -> V1DEType { self.de_type } - /// Destructures this `GenericV1DataElement` into just the - /// DE payload byte-buffer. + /// Destructures this `GenericV1DataElement` into just the DE payload byte-buffer. pub fn into_payload(self) -> ByteBuffer<127> { self.payload }
diff --git a/nearby/presence/np_ffi_core/src/serialize/v0.rs b/nearby/presence/np_ffi_core/src/serialize/v0.rs index 2d6b413..736925b 100644 --- a/nearby/presence/np_ffi_core/src/serialize/v0.rs +++ b/nearby/presence/np_ffi_core/src/serialize/v0.rs
@@ -19,9 +19,8 @@ use crate::utils::FfiEnum; use crate::v0::V0DataElement; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError}; -use np_adv; -use np_adv_dynamic; +use handle_map::{declare_handle_map, HandleLike, HandleMapFullError}; +use np_adv_dynamic::legacy::BoxedAdvConstructionError; /// A handle to a builder for V0 advertisements. #[derive(Clone, Copy)] @@ -32,26 +31,29 @@ } impl V0AdvertisementBuilder { - /// Attempts to add the given data element to the V0 - /// advertisement builder behind this handle. + /// Gets the kind of advertisement builder (public/encrypted). + pub fn kind(&self) -> AdvertisementBuilderKind { + self.kind + } + + /// Attempts to add the given data element to the V0 advertisement builder behind this handle. + /// This function does not take ownership of the handle. pub fn add_de(&self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure> { match self.handle.get_mut() { Ok(mut adv_builder_write_guard) => adv_builder_write_guard.add_de(de), Err(_) => Ok(AddV0DEResult::InvalidAdvertisementBuilderHandle), } } - /// Attempts to serialize the contents of the advertisement builder - /// behind this handle to bytes. Assuming that the handle is valid, - /// this operation will always result in the contents behind the - /// advertisement builder handle being deallocated. + /// Attempts to serialize the contents of the advertisement builder behind this handle to + /// bytes. This function takes ownership of the handle. pub fn into_advertisement(self) -> SerializeV0AdvertisementResult { match self.handle.deallocate() { Ok(adv_builder) => adv_builder.into_advertisement(), Err(_) => SerializeV0AdvertisementResult::InvalidAdvertisementBuilderHandle, } } - /// Attempts to deallocate the V0 advertisement builder - /// behind this handle. + /// Attempts to deallocate the V0 advertisement builder behind this handle. This function takes + /// ownership of the handle. pub fn deallocate(self) -> DeallocateResult { self.handle.deallocate().map(|_| ()).into() } @@ -108,45 +110,42 @@ declare_enum_cast! {into_success, Success, V0AdvertisementBuilder } } -/// Creates a new V0 advertisement builder for a public advertisement. +/// Creates a new V0 advertisement builder for a public advertisement. The caller is given +/// ownership of the created handle. pub fn create_v0_public_advertisement_builder() -> CreateV0AdvertisementBuilderResult { V0AdvertisementBuilderHandle::allocate(V0AdvertisementBuilderInternals::new_public) .map(|handle| V0AdvertisementBuilder { kind: AdvertisementBuilderKind::Public, handle }) .into() } -/// Creates a new V0 advertisement builder for an encrypted advertisement. +/// Creates a new V0 advertisement builder for an encrypted advertisement. The caller is given +/// ownership of the created handle. pub fn create_v0_encrypted_advertisement_builder( broadcast_cred: V0BroadcastCredential, - identity_type: EncryptedIdentityType, salt: FixedSizeArray<2>, ) -> CreateV0AdvertisementBuilderResult { V0AdvertisementBuilderHandle::allocate(move || { - V0AdvertisementBuilderInternals::new_ldt(broadcast_cred, identity_type, salt.into_array()) + V0AdvertisementBuilderInternals::new_ldt(broadcast_cred, salt.into_array()) }) .map(|handle| V0AdvertisementBuilder { kind: AdvertisementBuilderKind::Encrypted, handle }) .into() } -impl V0AdvertisementBuilder { - /// Gets the kind of advertisement builder (public/encrypted) - pub fn kind(&self) -> AdvertisementBuilderKind { - self.kind - } -} - /// Discriminant for `SerializeV0AdvertisementResult`. #[repr(u8)] pub enum SerializeV0AdvertisementResultKind { /// Serializing the advertisement to bytes was successful. Success = 0, + /// The advertisement builder handle was invalid. + InvalidAdvertisementBuilderHandle = 1, /// Serializing the advertisement to bytes failed /// because the data in the advertisement wasn't /// of an appropriate size for LDT encryption /// to succeed. - LdtError = 1, - /// The advertisement builder handle was invalid. - InvalidAdvertisementBuilderHandle = 2, + LdtError = 2, + /// Serializing an unencrypted adv failed because the adv data didn't meet the length + /// requirements. + UnencryptedError = 3, } /// The result of attempting to serialize the contents @@ -155,8 +154,9 @@ #[allow(missing_docs)] pub enum SerializeV0AdvertisementResult { Success(ByteBuffer<24>), - LdtError, InvalidAdvertisementBuilderHandle, + LdtError, + UnencryptedError, } impl SerializeV0AdvertisementResult { @@ -168,10 +168,11 @@ fn kind(&self) -> SerializeV0AdvertisementResultKind { match self { Self::Success(_) => SerializeV0AdvertisementResultKind::Success, - Self::LdtError => SerializeV0AdvertisementResultKind::LdtError, Self::InvalidAdvertisementBuilderHandle => { SerializeV0AdvertisementResultKind::InvalidAdvertisementBuilderHandle } + Self::LdtError => SerializeV0AdvertisementResultKind::LdtError, + Self::UnencryptedError => SerializeV0AdvertisementResultKind::UnencryptedError, } } } @@ -183,32 +184,23 @@ impl V0AdvertisementBuilderInternals { pub(crate) fn new_public() -> Self { - Self::new(np_adv::PublicIdentity.into()) + Self::new(np_adv::legacy::serialize::UnencryptedEncoder.into()) } - pub(crate) fn new_ldt( - broadcast_cred: V0BroadcastCredential, - identity_type: EncryptedIdentityType, - salt: [u8; 2], - ) -> Self { + pub(crate) fn new_ldt(broadcast_cred: V0BroadcastCredential, salt: [u8; 2]) -> Self { // TODO: What do about salts? Need to prevent re-use fo the same salt, // but have no current rich representation of used salts... - let salt = ldt_np_adv::LegacySalt::from(salt); - let identity_type = identity_type.into(); + let salt = ldt_np_adv::V0Salt::from(salt); let internal_broadcast_cred = broadcast_cred.into_internal(); - let identity = np_adv::legacy::serialize::LdtIdentity::new( - identity_type, - salt, - &internal_broadcast_cred, - ); + let identity = np_adv::legacy::serialize::LdtEncoder::new(salt, &internal_broadcast_cred); Self::new(identity.into()) } - fn new(identity: np_adv_dynamic::legacy::BoxedIdentity<CryptoProviderImpl>) -> Self { + fn new(encoder: np_adv_dynamic::legacy::BoxedEncoder<CryptoProviderImpl>) -> Self { let adv_builder = - np_adv_dynamic::legacy::BoxedAdvBuilder::<CryptoProviderImpl>::new(identity); + np_adv_dynamic::legacy::BoxedAdvBuilder::<CryptoProviderImpl>::new(encoder); Self { adv_builder } } fn add_de(&mut self, de: V0DataElement) -> Result<AddV0DEResult, InvalidStackDataStructure> { - let to_boxed = np_adv_dynamic::legacy::ToBoxedDataElementBundle::try_from(de)?; + let to_boxed = np_adv_dynamic::legacy::ToBoxedSerializeDataElement::try_from(de)?; use np_adv::legacy::serialize::AddDataElementError; use np_adv_dynamic::legacy::BoxedAddDataElementError; match self.adv_builder.add_data_element(to_boxed) { @@ -222,22 +214,19 @@ } } fn into_advertisement(self) -> SerializeV0AdvertisementResult { - match self.adv_builder.into_advertisement() { - Ok(serialized_bytes) => { - let byte_buffer = ByteBuffer::from_array_view(serialized_bytes); - SerializeV0AdvertisementResult::Success(byte_buffer) - } - Err(np_adv_dynamic::legacy::BoxedAdvConstructionError::Ldt(_)) => { - SerializeV0AdvertisementResult::LdtError - } - } - } -} - -fn get_v0_advertisement_builder_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_v0_advertisement_builders(), + self.adv_builder + .into_advertisement() + .map(|serialized_bytes| { + SerializeV0AdvertisementResult::Success(ByteBuffer::from_array_view( + serialized_bytes, + )) + }) + .unwrap_or_else(|e| match e { + BoxedAdvConstructionError::Ldt(_) => SerializeV0AdvertisementResult::LdtError, + BoxedAdvConstructionError::Unencrypted(_) => { + SerializeV0AdvertisementResult::UnencryptedError + } + }) } } @@ -250,7 +239,7 @@ declare_handle_map!( advertisement_builder, - super::get_v0_advertisement_builder_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::V0AdvertisementBuilderHandle, super::V0AdvertisementBuilderInternals );
diff --git a/nearby/presence/np_ffi_core/src/serialize/v1.rs b/nearby/presence/np_ffi_core/src/serialize/v1.rs index d48a725..c87446f 100644 --- a/nearby/presence/np_ffi_core/src/serialize/v1.rs +++ b/nearby/presence/np_ffi_core/src/serialize/v1.rs
@@ -19,9 +19,7 @@ use crate::utils::FfiEnum; use crate::v1::V1VerificationMode; use crypto_provider_default::CryptoProviderImpl; -use handle_map::{declare_handle_map, HandleLike, HandleMapDimensions, HandleMapFullError}; -use np_adv; -use np_adv_dynamic; +use handle_map::{declare_handle_map, HandleLike, HandleMapFullError}; /// A handle to a builder for V1 advertisements. #[derive(Clone, Copy)] @@ -32,21 +30,24 @@ } impl V1AdvertisementBuilder { - /// Attempts to create a builder for a new public section within - /// this advertisement, returning a handle to the newly-created - /// section builder if successful. + /// Attempts to create a builder for a new public section within this advertisement, returning + /// an owned handle to the newly-created section builder if successful. /// - /// This method may fail if there is another currently-active - /// section builder for the same advertisement builder, if the - /// kind of section being added does not match the advertisement - /// type (public/encrypted), or if the section would not manage - /// to fit within the enclosing advertisement. + /// This method may fail if there is another currently-active section builder for the same + /// advertisement builder, if the kind of section being added does not match the advertisement + /// type (public/encrypted), or if the section would not manage to fit within the enclosing + /// advertisement. pub fn public_section_builder(&self) -> CreateV1SectionBuilderResult { self.section_builder_internals(|internals| internals.public_section_builder()) } - /// Attempts to create a builder for a new encrypted section within - /// this advertisement, returning a handle to the newly-created - /// section builder if successful. + + /// Gets the kind of advertisement builder (public/encrypted) + pub fn kind(&self) -> AdvertisementBuilderKind { + self.kind + } + + /// Attempts to create a builder for a new encrypted section within this advertisement, + /// returning an owned handle to the newly-created section builder if successful. /// /// The identity details for the new section builder may be specified /// via providing the broadcast credential data, the kind of encrypted @@ -61,18 +62,17 @@ pub fn encrypted_section_builder( &self, broadcast_cred: V1BroadcastCredential, - identity_type: EncryptedIdentityType, verification_mode: V1VerificationMode, ) -> CreateV1SectionBuilderResult { self.section_builder_internals(move |internals| { - internals.encrypted_section_builder(broadcast_cred, identity_type, verification_mode) + internals.encrypted_section_builder(broadcast_cred, verification_mode) }) } - /// Attempts to serialize the contents of the advertisement builder - /// behind this handle to bytes. Assuming that the handle is valid, - /// this operation will always result in the contents behind the - /// advertisement builder handle being deallocated. + /// Attempts to serialize the contents of the advertisement builder behind this handle to + /// bytes. Assuming that the handle is valid, this operation will always take ownership of the + /// handle and result in the contents behind the advertisement builder handle being + /// deallocated. pub fn into_advertisement(self) -> SerializeV1AdvertisementResult { match self.handle.deallocate() { Ok(adv_builder) => adv_builder.into_advertisement(), @@ -162,25 +162,13 @@ .into() } -impl V1AdvertisementBuilder { - /// Gets the kind of advertisement builder (public/encrypted) - pub fn kind(&self) -> AdvertisementBuilderKind { - self.kind - } -} - pub(crate) enum V1AdvertisementBuilderState { /// Internal state for when we have an active advertisement /// builder, but no currently-active section builder. Advertisement(np_adv_dynamic::extended::BoxedAdvBuilder), /// Internal state for when we have both an active advertisement /// builder and an active section builder. - Section( - np_adv_dynamic::extended::BoxedSectionBuilder< - np_adv::extended::serialize::AdvBuilder, - CryptoProviderImpl, - >, - ), + Section(np_adv_dynamic::extended::BoxedSectionBuilder<np_adv::extended::serialize::AdvBuilder>), } /// Internal version of errors which may be raised when @@ -279,12 +267,12 @@ /// of the newly-added section builder. pub(crate) fn section_builder_internal( &mut self, - identity: np_adv_dynamic::extended::BoxedIdentity<CryptoProviderImpl>, + identity: np_adv_dynamic::extended::BoxedEncoder, ) -> Result<usize, SectionBuilderError> { let state = self.state.take(); match state { Some(V1AdvertisementBuilderState::Advertisement(adv_builder)) => { - match adv_builder.into_section_builder::<CryptoProviderImpl>(identity) { + match adv_builder.into_section_builder(identity) { Ok(section_builder) => { let section_index = section_builder.section_index(); self.state = Some(V1AdvertisementBuilderState::Section(section_builder)); @@ -307,38 +295,34 @@ } pub(crate) fn public_section_builder(&mut self) -> Result<usize, SectionBuilderError> { - let identity = np_adv_dynamic::extended::BoxedIdentity::PublicIdentity; + let identity = np_adv_dynamic::extended::BoxedEncoder::Unencrypted; self.section_builder_internal(identity) } pub(crate) fn encrypted_section_builder( &mut self, broadcast_cred: V1BroadcastCredential, - identity_type: EncryptedIdentityType, verification_mode: V1VerificationMode, ) -> Result<usize, SectionBuilderError> { let mut rng = get_global_crypto_rng(); let rng = rng.get_rng(); - let identity_type = identity_type.into(); let internal_broadcast_cred = broadcast_cred.into_internal(); - let identity = match verification_mode { + let encoder = match verification_mode { V1VerificationMode::Mic => { - let encoder = np_adv::extended::serialize::MicEncryptedSectionEncoder::< - CryptoProviderImpl, - >::new_random_salt( - rng, identity_type, &internal_broadcast_cred - ); - np_adv_dynamic::extended::BoxedIdentity::MicEncrypted(encoder) + let encoder = + np_adv::extended::serialize::MicEncryptedSectionEncoder::<_>::new_wrapped_salt::< + CryptoProviderImpl, + >(rng, &internal_broadcast_cred); + np_adv_dynamic::extended::BoxedEncoder::MicEncrypted(encoder) } V1VerificationMode::Signature => { - let encoder = np_adv::extended::serialize::SignedEncryptedSectionEncoder::< - CryptoProviderImpl, - >::new_random_salt( - rng, identity_type, &internal_broadcast_cred - ); - np_adv_dynamic::extended::BoxedIdentity::SignedEncrypted(encoder) + let encoder = + np_adv::extended::serialize::SignedEncryptedSectionEncoder::new_random_salt::< + CryptoProviderImpl, + >(rng, &internal_broadcast_cred); + np_adv_dynamic::extended::BoxedEncoder::SignedEncrypted(encoder) } }; - self.section_builder_internal(identity) + self.section_builder_internal(encoder) } fn into_advertisement(self) -> SerializeV1AdvertisementResult { match self.state { @@ -351,13 +335,6 @@ } } -fn get_v1_advertisement_builder_handle_map_dimensions() -> HandleMapDimensions { - HandleMapDimensions { - num_shards: global_num_shards(), - max_active_handles: global_max_num_v1_advertisement_builders(), - } -} - /// A `#[repr(C)]` handle to a value of type `V1AdvertisementBuilderInternals` #[repr(C)] #[derive(Clone, Copy, PartialEq, Eq)] @@ -367,7 +344,7 @@ declare_handle_map!( advertisement_builder, - super::get_v1_advertisement_builder_handle_map_dimensions(), + crate::common::default_handle_map_dimensions(), super::V1AdvertisementBuilderHandle, super::V1AdvertisementBuilderInternals ); @@ -501,21 +478,18 @@ } impl NextV1DE16ByteSaltResult { - declare_enum_cast! {into_success, Success, FixedSizeArray<16> } -} - -impl From<Option<np_adv::extended::serialize::DeSalt<CryptoProviderImpl>>> - for NextV1DE16ByteSaltResult -{ - fn from(maybe_salt: Option<np_adv::extended::serialize::DeSalt<CryptoProviderImpl>>) -> Self { - match maybe_salt.and_then(|salt| salt.derive::<16>()) { + fn new_from_de_salt(salt: Option<np_adv::extended::serialize::DeSalt>) -> Self { + match salt.and_then(|salt| salt.derive::<16, CryptoProviderImpl>()) { Some(salt) => NextV1DE16ByteSaltResult::Success(FixedSizeArray::from_array(salt)), None => NextV1DE16ByteSaltResult::Error, } } + + declare_enum_cast! {into_success, Success, FixedSizeArray<16> } } -/// A handle to a builder for V1 sections. +/// A handle to a builder for V1 sections. This is not a unique handle; it is the same handle as +/// the advertisement builder the section builder was originated from. #[derive(Clone, Copy)] #[repr(C)] pub struct V1SectionBuilder { @@ -537,7 +511,8 @@ // matches the index of the section currently under construction. let actual_section_index = section_builder.section_index() as u8; if self.section_index == actual_section_index { - let updated_adv_builder = section_builder.add_to_advertisement(); + let updated_adv_builder = + section_builder.add_to_advertisement::<CryptoProviderImpl>(); adv_builder.state = Some(V1AdvertisementBuilderState::Advertisement( updated_adv_builder, )); @@ -564,7 +539,9 @@ /// is a public section. pub fn next_de_salt(&self) -> NextV1DE16ByteSaltResult { self.try_apply_to_internals( - |section_builder| section_builder.next_de_salt().into(), + |section_builder| { + NextV1DE16ByteSaltResult::new_from_de_salt(section_builder.next_de_salt()) + }, NextV1DE16ByteSaltResult::Error, ) } @@ -598,7 +575,6 @@ func: impl FnOnce( &mut np_adv_dynamic::extended::BoxedSectionBuilder< np_adv::extended::serialize::AdvBuilder, - CryptoProviderImpl, >, ) -> R, invalid_handle_error: R, @@ -658,9 +634,6 @@ mod tests { use super::*; - const EMPTY_BROADCAST_CRED: V1BroadcastCredential = - V1BroadcastCredential::new([0; 32], [0; 16], [0; 32]); - fn state_is_advertisement_building(adv_builder_state: &V1AdvertisementBuilderState) -> bool { matches!(adv_builder_state, V1AdvertisementBuilderState::Advertisement(_)) } @@ -675,11 +648,7 @@ adv_builder.state.as_ref().expect("Adv builder state should be present."); assert!(state_is_advertisement_building(adv_builder_state)); let section_index = adv_builder - .encrypted_section_builder( - EMPTY_BROADCAST_CRED, - EncryptedIdentityType::Private, - V1VerificationMode::Mic, - ) + .encrypted_section_builder(empty_broadcast_cred(), V1VerificationMode::Mic) .expect("Should be able to build the first section."); assert_eq!(section_index, 0); @@ -689,12 +658,12 @@ assert!(!state_is_advertisement_building(adv_builder_state)); let double_build_error = adv_builder - .encrypted_section_builder( - EMPTY_BROADCAST_CRED, - EncryptedIdentityType::Private, - V1VerificationMode::Mic, - ) + .encrypted_section_builder(empty_broadcast_cred(), V1VerificationMode::Mic) .expect_err("Shouldn't be able to start a new section builder with an unclosed one."); assert_eq!(double_build_error, SectionBuilderError::UnclosedActiveSection); } + + fn empty_broadcast_cred() -> V1BroadcastCredential { + V1BroadcastCredential::new([0; 32], [0; 16].into(), [0; 32]) + } }
diff --git a/nearby/presence/np_ffi_core/src/utils.rs b/nearby/presence/np_ffi_core/src/utils.rs index b1495b9..4876645 100644 --- a/nearby/presence/np_ffi_core/src/utils.rs +++ b/nearby/presence/np_ffi_core/src/utils.rs
@@ -17,6 +17,10 @@ /// Type-level predicate for handle types which uniformly hold a lock /// for longer than some other handle type in API calls. +/// +/// Largely an informative marker trait used to indicate the +/// lock ordering on types. +#[allow(dead_code)] pub(crate) trait LocksLongerThan<H: HandleLike>: HandleLike {} /// Trait which canonicalizes the relationship between FFI
diff --git a/nearby/presence/np_ffi_core/src/v0.rs b/nearby/presence/np_ffi_core/src/v0.rs index 89a427c..16b7b21 100644 --- a/nearby/presence/np_ffi_core/src/v0.rs +++ b/nearby/presence/np_ffi_core/src/v0.rs
@@ -18,8 +18,11 @@ use crate::common::InvalidStackDataStructure; use crate::serialize::AdvertisementBuilderKind; use crate::utils::FfiEnum; -use np_adv::legacy::actions::ActionsDataElement; -use np_adv::legacy::{data_elements as np_adv_de, Ciphertext, PacketFlavorEnum, Plaintext}; +use np_adv::{ + legacy::data_elements::actions::ActionsDataElement, + legacy::{data_elements as np_adv_de, Ciphertext, PacketFlavorEnum, Plaintext}, +}; +use strum::IntoEnumIterator; /// Discriminant for `V0DataElement`. #[repr(u8)] @@ -27,11 +30,11 @@ /// A transmission Power (Tx Power) data-element. /// The associated payload may be obtained via /// `V0DataElement#into_tx_power`. - TxPower = 0, + TxPower = 1, /// The Actions data-element. /// The associated payload may be obtained via /// `V0DataElement#into_actions`. - Actions = 1, + Actions = 2, } /// Representation of a V0 data element. @@ -43,7 +46,7 @@ Actions(V0Actions), } -impl TryFrom<V0DataElement> for np_adv_dynamic::legacy::ToBoxedDataElementBundle { +impl TryFrom<V0DataElement> for np_adv_dynamic::legacy::ToBoxedSerializeDataElement { type Error = InvalidStackDataStructure; fn try_from(de: V0DataElement) -> Result<Self, InvalidStackDataStructure> { match de { @@ -53,14 +56,14 @@ } } -impl<F: np_adv::legacy::PacketFlavor> From<np_adv::legacy::deserialize::PlainDataElement<F>> +impl<F: np_adv::legacy::PacketFlavor> From<np_adv::legacy::deserialize::DeserializedDataElement<F>> for V0DataElement { - fn from(de: np_adv::legacy::deserialize::PlainDataElement<F>) -> Self { - use np_adv::legacy::deserialize::PlainDataElement; + fn from(de: np_adv::legacy::deserialize::DeserializedDataElement<F>) -> Self { + use np_adv::legacy::deserialize::DeserializedDataElement; match de { - PlainDataElement::Actions(x) => V0DataElement::Actions(x.into()), - PlainDataElement::TxPower(x) => V0DataElement::TxPower(x.into()), + DeserializedDataElement::Actions(x) => V0DataElement::Actions(x.into()), + DeserializedDataElement::TxPower(x) => V0DataElement::TxPower(x.into()), } } } @@ -124,8 +127,7 @@ } impl TxPower { - /// Attempts to construct a new TxPower from - /// the given signed-byte value. + /// Attempts to construct a new TxPower from the given signed-byte value. pub fn build_from_signed_byte(tx_power: i8) -> BuildTxPowerResult { match np_adv::shared_data::TxPower::try_from(tx_power) { Ok(_) => BuildTxPowerResult::Success(Self { tx_power }), @@ -138,13 +140,13 @@ } } -impl From<np_adv_de::TxPowerDataElement> for TxPower { - fn from(de: np_adv_de::TxPowerDataElement) -> Self { +impl From<np_adv_de::tx_power::TxPowerDataElement> for TxPower { + fn from(de: np_adv_de::tx_power::TxPowerDataElement) -> Self { Self { tx_power: de.tx_power_value() } } } -impl TryFrom<TxPower> for np_adv_dynamic::legacy::ToBoxedDataElementBundle { +impl TryFrom<TxPower> for np_adv_dynamic::legacy::ToBoxedSerializeDataElement { type Error = InvalidStackDataStructure; fn try_from(value: TxPower) -> Result<Self, InvalidStackDataStructure> { np_adv::shared_data::TxPower::try_from(value.as_i8()) @@ -153,80 +155,6 @@ } } -/// Discriminant for `BuildContextSyncSeqNumResult`. -#[repr(u8)] -#[derive(Clone, Copy)] -pub enum BuildContextSyncSeqNumResultKind { - /// The sequence number was outside the allowed - /// 0-15 single-nibble range. - OutOfRange = 0, - /// The sequence number was in range, - /// and so a `ContextSyncSeqNum` was constructed. - Success = 1, -} - -/// Result type for attempting to construct a -/// ContextSyncSeqNum from an unsigned byte. -#[repr(C)] -#[allow(missing_docs)] -pub enum BuildContextSyncSeqNumResult { - OutOfRange, - Success(ContextSyncSeqNum), -} - -impl FfiEnum for BuildContextSyncSeqNumResult { - type Kind = BuildContextSyncSeqNumResultKind; - fn kind(&self) -> Self::Kind { - match self { - Self::OutOfRange => BuildContextSyncSeqNumResultKind::OutOfRange, - Self::Success(_) => BuildContextSyncSeqNumResultKind::Success, - } - } -} - -impl BuildContextSyncSeqNumResult { - declare_enum_cast! {into_success, Success, ContextSyncSeqNum} -} -/// Representation of a context-sync sequence number. -#[derive(Clone, Copy)] -#[repr(C)] -pub struct ContextSyncSeqNum { - value: u8, -} - -impl ContextSyncSeqNum { - /// Attempts to build a new context sync sequence number - /// from the given unsigned byte. - pub fn build_from_unsigned_byte(value: u8) -> BuildContextSyncSeqNumResult { - match np_adv::shared_data::ContextSyncSeqNum::try_from(value) { - Ok(_) => BuildContextSyncSeqNumResult::Success(Self { value }), - Err(_) => BuildContextSyncSeqNumResult::OutOfRange, - } - } - /// Yields this context sync sequence number - /// as a u8. - pub fn as_u8(&self) -> u8 { - self.value - } -} - -impl From<np_adv::shared_data::ContextSyncSeqNum> for ContextSyncSeqNum { - fn from(value: np_adv::shared_data::ContextSyncSeqNum) -> Self { - let value = value.as_u8(); - Self { value } - } -} - -impl TryFrom<ContextSyncSeqNum> for np_adv_dynamic::legacy::ToBoxedActionElement { - type Error = InvalidStackDataStructure; - fn try_from(value: ContextSyncSeqNum) -> Result<Self, Self::Error> { - let value = value.as_u8(); - np_adv::shared_data::ContextSyncSeqNum::try_from(value) - .map(np_adv_dynamic::legacy::ToBoxedActionElement::ContextSyncSeqNum) - .map_err(|_| InvalidStackDataStructure) - } -} - /// Representation of the Actions DE in V0. #[derive(Clone, Copy)] #[repr(C)] @@ -237,7 +165,7 @@ Encrypted(V0ActionBits), } -impl TryFrom<V0Actions> for np_adv_dynamic::legacy::ToBoxedDataElementBundle { +impl TryFrom<V0Actions> for np_adv_dynamic::legacy::ToBoxedSerializeDataElement { type Error = InvalidStackDataStructure; fn try_from(value: V0Actions) -> Result<Self, InvalidStackDataStructure> { let boxed_action_bits = np_adv_dynamic::legacy::BoxedActionBits::try_from(value)?; @@ -245,9 +173,7 @@ } } -impl<F: np_adv::legacy::PacketFlavor> From<np_adv::legacy::actions::ActionsDataElement<F>> - for V0Actions -{ +impl<F: np_adv::legacy::PacketFlavor> From<ActionsDataElement<F>> for V0Actions { fn from(value: ActionsDataElement<F>) -> Self { match F::ENUM_VARIANT { PacketFlavorEnum::Plaintext => { @@ -262,57 +188,102 @@ #[repr(C)] #[derive(Clone, Copy)] -/// The bitfield data of a VOActions data element +/// The bitfield data of a V0Actions data element pub struct V0ActionBits { bitfield: u32, } -#[derive(Clone, Copy)] +impl From<u32> for V0ActionBits { + fn from(bitfield: u32) -> Self { + // No need to validate here. Validation of this struct is done at all places where it is + // taken as a parameter. See [`InvalidStackDataStructure`]. Since this struct is + // `#[repr(C)]` if rules were enforced here, they could be broken by a foreign language + // user. + Self { bitfield } + } +} + +#[derive(Clone, Copy, strum_macros::EnumIter)] #[allow(missing_docs)] #[repr(u8)] /// The possible boolean action types which can be present in an Actions data element -pub enum BooleanActionType { +pub enum ActionType { + CrossDevSdk = 1, + CallTransfer = 4, ActiveUnlock = 8, NearbyShare = 9, InstantTethering = 10, PhoneHub = 11, - PresenceManager = 12, - Finder = 13, - FastPairSass = 14, } -impl BooleanActionType { +#[derive(Clone, Copy, Debug)] +/// The given int is out of range for conversion. +pub struct TryFromIntError; + +impl From<core::num::TryFromIntError> for TryFromIntError { + fn from(_: core::num::TryFromIntError) -> Self { + Self + } +} + +impl TryFrom<u8> for ActionType { + type Error = TryFromIntError; + fn try_from(n: u8) -> Result<Self, Self::Error> { + // cast is safe since it's a repr(u8) unit enum + Self::iter().find(|t| *t as u8 == n).ok_or(TryFromIntError) + } +} + +impl ActionType { pub(crate) fn as_boxed_action_element( &self, value: bool, ) -> np_adv_dynamic::legacy::ToBoxedActionElement { use np_adv_dynamic::legacy::ToBoxedActionElement; match self { + Self::CrossDevSdk => ToBoxedActionElement::CrossDevSdk(value), + Self::CallTransfer => ToBoxedActionElement::CallTransfer(value), Self::ActiveUnlock => ToBoxedActionElement::ActiveUnlock(value), Self::NearbyShare => ToBoxedActionElement::NearbyShare(value), Self::InstantTethering => ToBoxedActionElement::InstantTethering(value), Self::PhoneHub => ToBoxedActionElement::PhoneHub(value), - Self::PresenceManager => ToBoxedActionElement::PresenceManager(value), - Self::Finder => ToBoxedActionElement::Finder(value), - Self::FastPairSass => ToBoxedActionElement::FastPairSass(value), } } } -impl From<BooleanActionType> for np_adv::legacy::actions::ActionType { - fn from(value: BooleanActionType) -> Self { +impl From<ActionType> for np_adv::legacy::data_elements::actions::ActionType { + fn from(value: ActionType) -> Self { match value { - BooleanActionType::ActiveUnlock => np_adv::legacy::actions::ActionType::ActiveUnlock, - BooleanActionType::NearbyShare => np_adv::legacy::actions::ActionType::NearbyShare, - BooleanActionType::InstantTethering => { - np_adv::legacy::actions::ActionType::InstantTethering + ActionType::CrossDevSdk => { + np_adv::legacy::data_elements::actions::ActionType::CrossDevSdk } - BooleanActionType::PhoneHub => np_adv::legacy::actions::ActionType::PhoneHub, - BooleanActionType::Finder => np_adv::legacy::actions::ActionType::Finder, - BooleanActionType::FastPairSass => np_adv::legacy::actions::ActionType::FastPairSass, - BooleanActionType::PresenceManager => { - np_adv::legacy::actions::ActionType::PresenceManager + ActionType::CallTransfer => { + np_adv::legacy::data_elements::actions::ActionType::CallTransfer } + ActionType::ActiveUnlock => { + np_adv::legacy::data_elements::actions::ActionType::ActiveUnlock + } + ActionType::NearbyShare => { + np_adv::legacy::data_elements::actions::ActionType::NearbyShare + } + ActionType::InstantTethering => { + np_adv::legacy::data_elements::actions::ActionType::InstantTethering + } + ActionType::PhoneHub => np_adv::legacy::data_elements::actions::ActionType::PhoneHub, + } + } +} + +// ensure bidirectional mapping +impl From<np_adv::legacy::data_elements::actions::ActionType> for ActionType { + fn from(value: np_adv_de::actions::ActionType) -> Self { + match value { + np_adv_de::actions::ActionType::CrossDevSdk => ActionType::CrossDevSdk, + np_adv_de::actions::ActionType::CallTransfer => ActionType::CallTransfer, + np_adv_de::actions::ActionType::ActiveUnlock => ActionType::ActiveUnlock, + np_adv_de::actions::ActionType::NearbyShare => ActionType::NearbyShare, + np_adv_de::actions::ActionType::InstantTethering => ActionType::InstantTethering, + np_adv_de::actions::ActionType::PhoneHub => ActionType::PhoneHub, } } } @@ -334,17 +305,19 @@ fn try_from(actions: V0Actions) -> Result<Self, InvalidStackDataStructure> { match actions { V0Actions::Plaintext(action_bits) => { - let bits = np_adv::legacy::actions::ActionBits::<Plaintext>::try_from( - action_bits.bitfield, - ) - .map_err(|_| InvalidStackDataStructure)?; + let bits = + np_adv::legacy::data_elements::actions::ActionBits::<Plaintext>::try_from( + action_bits.bitfield, + ) + .map_err(|_| InvalidStackDataStructure)?; Ok(bits.into()) } V0Actions::Encrypted(action_bits) => { - let bits = np_adv::legacy::actions::ActionBits::<Ciphertext>::try_from( - action_bits.bitfield, - ) - .map_err(|_| InvalidStackDataStructure)?; + let bits = + np_adv::legacy::data_elements::actions::ActionBits::<Ciphertext>::try_from( + action_bits.bitfield, + ) + .map_err(|_| InvalidStackDataStructure)?; Ok(bits.into()) } } @@ -410,13 +383,10 @@ /// Return whether a boolean action type is set in this data element #[allow(clippy::expect_used)] - pub fn has_action( - &self, - action_type: BooleanActionType, - ) -> Result<bool, InvalidStackDataStructure> { + pub fn has_action(&self, action_type: ActionType) -> Result<bool, InvalidStackDataStructure> { let boxed_action_bits = np_adv_dynamic::legacy::BoxedActionBits::try_from(*self)?; let action_type = action_type.into(); - Ok(boxed_action_bits.has_action(&action_type).expect("BooleanActionType only has one bit")) + Ok(boxed_action_bits.has_action(action_type)) } /// Attempts to set the given action bit to the given boolean value. @@ -427,7 +397,7 @@ /// unaltered. pub fn set_action( self, - action_type: BooleanActionType, + action_type: ActionType, value: bool, ) -> Result<SetV0ActionResult, InvalidStackDataStructure> { let mut boxed_action_bits = np_adv_dynamic::legacy::BoxedActionBits::try_from(self)?; @@ -437,25 +407,4 @@ Err(_) => Ok(SetV0ActionResult::Error(self)), } } - - /// Sets the context sequence number for this data element. - #[allow(clippy::expect_used)] - pub fn set_context_sync_seq_num( - self, - value: ContextSyncSeqNum, - ) -> Result<Self, InvalidStackDataStructure> { - let mut boxed_action_bits = np_adv_dynamic::legacy::BoxedActionBits::try_from(self)?; - let boxed_action_element = np_adv_dynamic::legacy::ToBoxedActionElement::try_from(value)?; - boxed_action_bits - .set_action(boxed_action_element) - .expect("Context sync sequence number always may be present"); - Ok(boxed_action_bits.into()) - } - - /// Return the context sequence number from this data element - #[allow(clippy::expect_used)] - pub fn get_context_sync_seq_num(&self) -> Result<ContextSyncSeqNum, InvalidStackDataStructure> { - let boxed_action_bits = np_adv_dynamic::legacy::BoxedActionBits::try_from(*self)?; - Ok(boxed_action_bits.get_context_sync_seq_num().into()) - } }
diff --git a/nearby/presence/np_hkdf/Cargo.toml b/nearby/presence/np_hkdf/Cargo.toml index 45e40da..cd7fb4c 100644 --- a/nearby/presence/np_hkdf/Cargo.toml +++ b/nearby/presence/np_hkdf/Cargo.toml
@@ -17,9 +17,10 @@ xts_aes.workspace = true [dev-dependencies] -crypto_provider_default.workspace = true +crypto_provider_default = { workspace = true, features = ["rustcrypto"] } rand_ext.workspace = true test_helper.workspace = true +test_vector_hkdf.workspace = true anyhow.workspace = true criterion.workspace = true
diff --git a/nearby/presence/np_hkdf/benches/np_hkdf.rs b/nearby/presence/np_hkdf/benches/np_hkdf.rs index bec3b0e..0380d78 100644 --- a/nearby/presence/np_hkdf/benches/np_hkdf.rs +++ b/nearby/presence/np_hkdf/benches/np_hkdf.rs
@@ -17,6 +17,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use crypto_provider::{CryptoProvider, CryptoRng}; use crypto_provider_default::CryptoProviderImpl; +use np_hkdf::DerivedSectionKeys; use rand_ext::random_bytes; pub fn build_np_hkdf(c: &mut Criterion) { @@ -45,7 +46,7 @@ .collect::<Vec<_>>(); b.iter(|| { for hkdf in keys.iter() { - black_box(hkdf.extended_unsigned_metadata_key_hmac_key()); + black_box(hkdf.v1_mic_extended_salt_keys().identity_token_hmac_key()); } }); }); @@ -62,7 +63,7 @@ .collect::<Vec<_>>(); b.iter(|| { for hkdf in keys.iter() { - black_box(np_hkdf::UnsignedSectionKeys::aes_key(hkdf)); + black_box(hkdf.v1_mic_extended_salt_keys().aes_key()); } }); }); @@ -79,7 +80,7 @@ .collect::<Vec<_>>(); b.iter(|| { for hkdf in keys.iter() { - black_box(hkdf.legacy_ldt_key()); + black_box(hkdf.v0_ldt_key()); } }); });
diff --git a/nearby/presence/np_hkdf/resources/test/hkdf-test-vectors.json b/nearby/presence/np_hkdf/resources/test/hkdf-test-vectors.json index b4e283c..d0af65f 100644 --- a/nearby/presence/np_hkdf/resources/test/hkdf-test-vectors.json +++ b/nearby/presence/np_hkdf/resources/test/hkdf-test-vectors.json
@@ -1,2802 +1,3502 @@ [ { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "99D59E9A0A1761D40F4F28E1D56F4C25", - "derived_salt_first_section_no_de": "4D02FD0C02250E221A8C63A1A9865AE2", - "derived_salt_first_section_third_de": "8A72AE14A6EA06DAD91CC5970FBD005F", - "section_salt": "C561AB4667AA9D7E126E79F060BAD04F" + "key_seed_hkdf": { + "key_seed": "C73539A8BBF0270B0F15AC17442D664D0599FD63A6C9B913E1A4FDE3FD445229", + "v0_identity_token_hmac_key": "3EDE3135EFBB36DAA573469C4154DD3801D7A1A9DBF909EC9589C0F290395E09", + "v0_ldt_key": "FA79263B28CC411B6EF1D07A13D99E021D16E85C31963C86CA6413466F05F4ADC05EF9EAE5986F2C36525B366D88A05AC51CF105B09C98469341A6EC6E37C553", + "v0_metadata_nonce": "8A2952BCB4BB1A5131595884", + "v1_metadata_nonce": "2F68AE0A2D4A63436948F8A3", + "v1_mic_extended_salt_aes_key": "3C6AB7573EB60372377088D37FA71F28", + "v1_mic_extended_salt_identity_token_hmac_key": "AEAA5C7B9BEBC7ED47ACEEF2B4B15C957C7F18333DF05371CC5194928E4A75E1", + "v1_mic_extended_salt_mic_hmac_key": "77FAC801B7F4BFB45B66493109E5D2B8A1811046FE1B26FDD4911DFE83F22AE6", + "v1_mic_short_salt_aes_key": "6A4EA007544EB1F1F4FC3A09733A7636", + "v1_mic_short_salt_identity_token_hmac_key": "24CCCA1794C5267D0F31BFFD05933A3056DC866AE5CCC812D0BE992E741E3C70", + "v1_mic_short_salt_mic_hmac_key": "900CCE3E377FBF1A075F5FB96B2A670981624069DFCF8A99FF3CCB73AEDEC153", + "v1_signature_identity_token_hmac_key": "8C707D9DCB8C7965EF0DFB90C8781312135C0A8AD10388B939082947B0EEC5CF", + "v1_signature_section_aes_key": "EDB08293628753CF3BE7C28A65FF1A9D" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "05B8575BCA2486B5A1DD5D7D", - "extended_signed_metadata_key_hmac_key": "072C62C8F3A83F2ED0EEDD3107249160FF2ABEEDBEBA4607EF517A60F6640C7C", - "extended_signed_section_aes_key": "4DF7DE7DECCF54059C259EC7529D8AF8", - "extended_unsigned_metadata_key_hmac_key": "DC9FC71D78B822B6763ED1058E77DFCEF41B5F9F4810330AE034F962700EE225", - "extended_unsigned_section_aes_key": "A4E14FCB637F18E3B908635B67F4695B", - "extended_unsigned_section_mic_hmac_key": "C456B4C30D6E8F33B2D4010D656E3321ACF572EE09C831A87177B04F0F692AEF", - "key_seed": "E78C9A018A4B81DD837D9C7E2995B265E3363AAE9E9F7A46D1E0ECC81689D004", - "legacy_ldt_key": "E584BE2B557549287AAF196A765A0BB7F26F81210FFBA9AFE314ED0A4912BC4098779896121E6F0DAFFB30A70F358854C984611C4C249D48D8793F35512CBCE7", - "legacy_metadata_key_hmac_key": "EF9805022265A8B11D56B8E9EB2A17307EFC258EA1B8CEF70380BE6A3A3B1F43", - "legacy_metadata_nonce": "2ED7B79A45C428DFB747460B" + "v0_adv_salt_hkdf": { + "adv_salt": "F0EB", + "expanded_salt": "5267CC24373508BDD9CC45FE1BBFF13F" + }, + "v0_identity_token_hkdf": { + "expanded_key": "DC3DF85D25399054C997ABA4D0550C72", + "v0_identity_token": "84C66824B29BA5741EC22F1D3E77" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "202A", - "expanded_salt": "BBB2F537324B844F10631A119EB7C1C0" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8579", + "short_salt_nonce": "38C673E98F69BE47A67CD13D" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "EFB7E58C4EF1CE656C9D2691CD46880E", - "legacy_metadata_key": "E36847D19B3DB1715E6542D66205" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "DA0DEC97DD1B417639F5BABAD8F3EA65", + "derived_salt_nonce": "3D412EFE82132F641657B86BBB145803", + "derived_salt_third_de": "2F1011C59BF1CC8A1870CB124E8C2753", + "section_extended_salt": "C88D4D9DF5287AE88CC991A84CDEDAA4" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "3B9EB63E2B808E95384B37049EC52296", - "derived_salt_first_section_no_de": "DA32C8270314D33E521BD6D455CEBAED", - "derived_salt_first_section_third_de": "FED4AB32F733BBD3A1F6CC3568925182", - "section_salt": "E6F154A2B223214012758A37E5EEEF10" + "key_seed_hkdf": { + "key_seed": "3938C7007A29B73F1EE49941B99A569D154FF1CFA6B67701E84BA14D303E1414", + "v0_identity_token_hmac_key": "A1F9362118EFA8F8C10597C11D8E3351A8803C2832961916C4057DC6CB48DCFC", + "v0_ldt_key": "895E703E6017716499E617F2915C4655D25840D38CCA27E32941FDD82AA3FC2C2CB3B7F29444E96F7539B50951822CC56C137287A863FAF9709AFDF470392155", + "v0_metadata_nonce": "33920520D06381D8CB88C56A", + "v1_metadata_nonce": "D2AC980FCF2027E5C5317F6D", + "v1_mic_extended_salt_aes_key": "3DBE8FC106A237FBA6DDACA6EF045882", + "v1_mic_extended_salt_identity_token_hmac_key": "7FCEB04961C81354ECB3B8C933C0E57441EE02244615DC091690D34B85730038", + "v1_mic_extended_salt_mic_hmac_key": "B97F39D53AA3497347DC3D7DDB5F6399C3EC78A97844A4B1B6CA33D62A5610CF", + "v1_mic_short_salt_aes_key": "BD67C930144A6D49052DDD3100DEAC8C", + "v1_mic_short_salt_identity_token_hmac_key": "83741493B76DCB32684A90514D76E06AEFA48BF6CCA7E5FD88F62A21457D6B7C", + "v1_mic_short_salt_mic_hmac_key": "9C2C874DBFFA6A5DB88D8FAB3BC2E6B8453452A666407A970AB09586A729F64B", + "v1_signature_identity_token_hmac_key": "CE915CC5776983A0FA0D9952A2DB5B9362C413351C147E7A060161B94F668AE6", + "v1_signature_section_aes_key": "F5E624240876543285520E1E8E74F795" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "ABA8038F9AF71FC6C1DA0AA4", - "extended_signed_metadata_key_hmac_key": "D65DA42911CD5ED334C530F869DB03C6614CA35E6FA866D9E38E69C777ABB6DA", - "extended_signed_section_aes_key": "A017DA593FF63BDF6FE6F77ECFD2AB5E", - "extended_unsigned_metadata_key_hmac_key": "A38246B6BD7F50873ACB4C04E0EC64FC189F64055D297E0965D98EEE19173A10", - "extended_unsigned_section_aes_key": "6727FBCBDC7B6C29F3ED05346661ADD6", - "extended_unsigned_section_mic_hmac_key": "E5DC924147B60D7F39EAA86AD504DB3C37230DBF79EDAB9005150135443864BF", - "key_seed": "80FCB0995D122213A13491854547AE8DC1F9DA0FBCDC425EF8CAE2F1621B5123", - "legacy_ldt_key": "791FFF186FAB641481FA4F9CED1FA84BE86FD44118214C4D911C7FED6E72367DD7E7D516CA45EBA6F39140D735EAE911C9FD41FF64AA5A1D6FAB6945EF95ACC7", - "legacy_metadata_key_hmac_key": "FB0D2011320B53ADC656F21ADAC39599A84660CC06E01E6BF71FA3A13EC7017F", - "legacy_metadata_nonce": "65E4371B55813FF7B1EF282B" + "v0_adv_salt_hkdf": { + "adv_salt": "11F3", + "expanded_salt": "08286FAACBAC794BF268D0733E82E545" + }, + "v0_identity_token_hkdf": { + "expanded_key": "96661B2739A97E383181D6025942488A", + "v0_identity_token": "DFB8131F26DD0C193982BBDCB69B" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "8527", - "expanded_salt": "41DF3C96FD61381D21C6B33C4ABF109B" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "4218", + "short_salt_nonce": "F43CD28A64290DCCB5ED553A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D3CFD17D054FAEBD7E7FC121915090B3", - "legacy_metadata_key": "788B30E87219D982203B007557BE" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "2A5D5B1EE6E62646232D1ABECBF33804", + "derived_salt_nonce": "2890730B9A82A68AF81B88B2880E0CCB", + "derived_salt_third_de": "C493E8AB86C2BD5B5B7EA619D2E0E92F", + "section_extended_salt": "3BC347425EE1B8962BF6D5D340D53C9D" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "29F63E30C4CA477654EA633EF851EF2C", - "derived_salt_first_section_no_de": "9F1DA62A3038226B6E1A0B7BA3AE6735", - "derived_salt_first_section_third_de": "078A761182B0E4C9FAB615B1B5BD76F3", - "section_salt": "3EFE885D2597608370E56E69A0EBBE08" + "key_seed_hkdf": { + "key_seed": "520437E77A58A99A75D71BEABD7D787B8C570335DE0E1D9C0EDA2659EBA786E8", + "v0_identity_token_hmac_key": "CD255D8326E90A105F6CE79A2CD291A2775D414DF5E1BB2C5AB1FD2AD76BB6E3", + "v0_ldt_key": "279DD7CCD679EA8406C1682148A1312BED0A0DB6414809A23079125258011134C5574FBEE4BF9E1B74E1F5D0F911B52B902B0009D0BB7100CBE9872648E3DA5E", + "v0_metadata_nonce": "6F23E1EB5657CCE8961D23DC", + "v1_metadata_nonce": "B745A0F923AA18DE10CC11E5", + "v1_mic_extended_salt_aes_key": "8274C309B074B3A1D80E0D77AECF4897", + "v1_mic_extended_salt_identity_token_hmac_key": "443DDC3EB2D51ACBD8C79ED2B732946408FE79CC0336A21C5AB774B2373864C1", + "v1_mic_extended_salt_mic_hmac_key": "972931866621E2B8DD7FB76ABB8797C18B26C74974ED471F501102645DC76ECC", + "v1_mic_short_salt_aes_key": "E240E070654F3794C276D799CB23D5CE", + "v1_mic_short_salt_identity_token_hmac_key": "9AA904713C1F1146CEACD567C6BC4BC7B84F92660426D1FD633A42ECD3D4196D", + "v1_mic_short_salt_mic_hmac_key": "648A1D4915934BE8EA5C24CF747E2A17A2CEF1E655D98B0877F3B1DCF04441B9", + "v1_signature_identity_token_hmac_key": "2B3210B9D391E4D2CDA95368B8B66572975348748C382588AAF4664E2EFFC2D4", + "v1_signature_section_aes_key": "9FC3EB118E5472E3D0E1806BC8EEB6C4" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "BC01", + "expanded_salt": "1945A447FF4F02934C6381466192FA3A" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "3F20992295F10AD806832D05", - "extended_signed_metadata_key_hmac_key": "74273A7D5F63F7E8F319716489804EF7B0693EE94831B24B94DEC7916B3A7E75", - "extended_signed_section_aes_key": "95C76B3AB159ECC6AA7AF3806E065EC7", - "extended_unsigned_metadata_key_hmac_key": "91ACB7139211ABCEEFD27C3371D8E8E3DA4AA1EF62DE05331A6A97671E4C1E13", - "extended_unsigned_section_aes_key": "A6A6E1AB38E8D1E1734D8E6F2ED72F55", - "extended_unsigned_section_mic_hmac_key": "81DF7CFC39442A2A065D795A1B836FE11A1E9EDA04DDF5C206A6C5E35DB37442", - "key_seed": "49F89927FDFEE5496504B4A130919BA8967C66E28BEAD4525DFEFCC704A18423", - "legacy_ldt_key": "C298669D7FFAE75E0DF93574FBCB1FF2ED135A0211256FCD6942981B832FBE35AD444D1678697DAF07F5D8A9E117CC86C3E57BB6BDB8689DF9CF969F097E68BA", - "legacy_metadata_key_hmac_key": "AF3EBA58151897927BE02FD78E68AAF90675CD8D556800B736752426ECD48764", - "legacy_metadata_nonce": "BED3836FD96FD34EB7FC9983" + "v0_identity_token_hkdf": { + "expanded_key": "1AB857638876426CA721C616DE5BF65C", + "v0_identity_token": "F996D02678003CD71CE17004C2D7" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "BE30", - "expanded_salt": "66BC953964F357EE08DD1C7668A79D6A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "FDD7", + "short_salt_nonce": "E6CDA2BF1E867E1C76A878A7" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "8C16CCF3C80E07746B1F8471932A1FE5", - "legacy_metadata_key": "74135EB8B0F379AAA4D4478ADE7F" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "8A985AC6265F3067E13ABAA6218D6758", + "derived_salt_nonce": "DA89867F71A70412D2B00D8DA0454838", + "derived_salt_third_de": "A36B229A20A2A972401A843F84FA8D33", + "section_extended_salt": "967D99CE3EE6D79AE98B8037056760B9" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "82AD47824247F00924ECF0A43621BC57", - "derived_salt_first_section_no_de": "C737B65B994BF8CD872CA41BDB8A53A7", - "derived_salt_first_section_third_de": "9BB8BB55E1DE5129A43AC0EA937B4430", - "section_salt": "72C9E759C172DA23B71FB6B0C6ED8CC7" + "key_seed_hkdf": { + "key_seed": "94830D89A2B314388EF7B63C3C3F1D9C5558F07B1ABFF28FC336FB5F41079FA9", + "v0_identity_token_hmac_key": "727F82E28FC3F96E5BFE00A479C96FD8419921516CA1ABC2FD42C373FE9E328B", + "v0_ldt_key": "64A40560C4ABFF49B54A893522F75B2DB2A21BE79B44E7F9CAC3AD0E8E5FAB91BAFA76B2264EA081EE92DD94B6B0AD11295BACC6D44C9B7224E975542FE837C5", + "v0_metadata_nonce": "E1FFED6F1FBE0A7086DB29FD", + "v1_metadata_nonce": "1E765544661B31503FB0CC04", + "v1_mic_extended_salt_aes_key": "B3773653274143AD72C95F3C01A71D4C", + "v1_mic_extended_salt_identity_token_hmac_key": "811D7EE92ECC15D14A2EB005C17F072BB331834EFE623F0E2EF5E042672995AD", + "v1_mic_extended_salt_mic_hmac_key": "025D81497467CE23085944DB9AD50A5B8BBEF3F5036E9750A8EE3801CEA18EB9", + "v1_mic_short_salt_aes_key": "10F24F181454ED4663CC803642768DAF", + "v1_mic_short_salt_identity_token_hmac_key": "6B42C12D243ABBB7F2236EAFFE0C1A8B1654E25E3CF6416677D3462DF7402062", + "v1_mic_short_salt_mic_hmac_key": "52EECEDEEF2758E036A9748E8BF06287F8C6E70CCDB6017C9961A97E64B26FD4", + "v1_signature_identity_token_hmac_key": "591CE684D72DA16E9168381A2A8167F409E83662AF6713F3F68D8B753DA3174B", + "v1_signature_section_aes_key": "240792A759473821A1D8CBF99AE54AA4" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "480A", + "expanded_salt": "73CA056DC334741E6E6567853BE9AC0E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "80921E0D404179D9F04DC155", - "extended_signed_metadata_key_hmac_key": "B9B1F73D7FCFD25EB6A62B788032C71104926922C436A137B95A46D7B63C5EE6", - "extended_signed_section_aes_key": "85C1D9D14D09C0722DCFF12643CF2669", - "extended_unsigned_metadata_key_hmac_key": "F89C26264B27E1A265C60D69A20AE73222CE9E2F68E0F1D71C6DEF936C4092D0", - "extended_unsigned_section_aes_key": "43639BFCEBDF4EE61629156E04F92EA0", - "extended_unsigned_section_mic_hmac_key": "AF81B5A56EC2D2541E46AB2F9F583A48155A2F9BB272372E8064E446BE8A182A", - "key_seed": "286E2029CF579A26495BE93926BC663732C46DE57049C1A5E2BEBFE03A12A096", - "legacy_ldt_key": "ED36084F2492B19D07D5A09D174C16A01B8AFEAF27C86EC145CEAD08C8BE67A80BCFF79C40F7E63019B81821A715DFEFCA273F467A176C61D7A024BC245A6B8E", - "legacy_metadata_key_hmac_key": "2A48789FF8B93282B4D483566E9FF4DFB65AF5FBB869BAEF6C408465A310879D", - "legacy_metadata_nonce": "6803BD4BD4D435930449C17E" + "v0_identity_token_hkdf": { + "expanded_key": "C68D9064D5CBC769AA2ABBB035248851", + "v0_identity_token": "0CF9B87C144D6D444DBC98D3307A" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "3353", - "expanded_salt": "C86C20A42866236AB1CD9F1E815DDFD5" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "A5A8", + "short_salt_nonce": "20358E029A4BA3EF97796505" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "95E24D5EA5EBA3152427BF48A3781BDC", - "legacy_metadata_key": "4FE2300F2CA3C469959DC0A5510D" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "002B67A8C992EAEBCA8259FEC28289A4", + "derived_salt_nonce": "F202A0CB1EE7D8FCC9BABB9EB6304EF5", + "derived_salt_third_de": "F44C487244901DE5D96ABFD481BAC4CB", + "section_extended_salt": "69167A8D033BBB5E257E729AE62ED6E7" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "98C14D785DD885F3D039C8F84EB65B81", - "derived_salt_first_section_no_de": "94C66E08758D83DCE457073C6B911483", - "derived_salt_first_section_third_de": "1BAED8E606422F18BC5CCD3F649BAEE6", - "section_salt": "9D82CCB568AEFB50C4D1061D29220A63" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "05B2831B07DF537F173ED291", - "extended_signed_metadata_key_hmac_key": "D120FC54257B1EA765E2D210C6F77D5066404601BBAC598725BDE993CCA9D90B", - "extended_signed_section_aes_key": "52605A8345524539B05A4DD5DD7A51EC", - "extended_unsigned_metadata_key_hmac_key": "ED44D698082772261DB4F47F37999E5474523A75A5F046A671B9138086A31B7A", - "extended_unsigned_section_aes_key": "8A0EC8AE2F2177300A418614507F0F27", - "extended_unsigned_section_mic_hmac_key": "E7456EDF9F5B5F614FDF8C88BF45B897307E2A48405FE3DC0F4B6966E9693C04", - "key_seed": "4F1E079363BF2CF5C475F0D927C36B81FBEC8B4F323A0417184414914AC95ADB", - "legacy_ldt_key": "BCB0EFC03494AD2260CE8925A140E58FA12FF5C6D59B467D6C4C6F616D0DEE6212DF667F5144F29E6DB4F04443EC2143A429F49189D4B96B077469D12FB609B7", - "legacy_metadata_key_hmac_key": "E43D59616850DA473A9820F0F4215FB23E0BCBFF91360EC9A8DCB2166DD360FF", - "legacy_metadata_nonce": "EDE3166B65C4FFCE477B0344" + "key_seed": "98EB553FA5F60CCA72B5C7DD2C98E4FF839C728EEDA1A5B78C182CB94C58C714", + "v0_identity_token_hmac_key": "5D87D3A84F06E24BFE1E22E7E5FFEADABF6D583587B2615DC39117568E1C958D", + "v0_ldt_key": "C676CF2C50219632BF484FBCDBC3B6ED9BAF0114B03B7EDB3B4F6A8A3C977F07A72B19F74C71F800B65FBDB5147EDB38AFAF849B82BB7F9717DF1C1ED206F534", + "v0_metadata_nonce": "824779F6CC15BF01C3BDB03C", + "v1_metadata_nonce": "79B82382BAE70FE9F2C3EEEC", + "v1_mic_extended_salt_aes_key": "A1DFA7F844D8357A3E0E554770F26517", + "v1_mic_extended_salt_identity_token_hmac_key": "EBBE559CBF3D41AF04F599C3AC66A57C14A7983BB59805520E0F26BECAFB04FD", + "v1_mic_extended_salt_mic_hmac_key": "3B571385F9A85C437D7A0FDEF9193B643FB30A82C94FF4BEF03499E8FF8DE773", + "v1_mic_short_salt_aes_key": "7945B907207E26989E99CF22D75C5134", + "v1_mic_short_salt_identity_token_hmac_key": "F4C50FCBF4772A730A1A962A61DBA99993BC4E1FC823B09C591889A07B0848EF", + "v1_mic_short_salt_mic_hmac_key": "5BB027194D3274626B9F12F33EDF3894F48C74EC8643E979171F311AE56C6196", + "v1_signature_identity_token_hmac_key": "4606A5AE3B1A042E620FAE09883B0E2B60F2CBA0F55243C9E82BE0BCBA64AA4C", + "v1_signature_section_aes_key": "62ED38EF19133F282C78AD3BE7493419" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "D3B5", - "expanded_salt": "75DF7B4DAE71EAA2531A2A66BD67CC34" + "v0_adv_salt_hkdf": { + "adv_salt": "D77E", + "expanded_salt": "7224B61774E1B0F193E6E2B9C6828D47" + }, + "v0_identity_token_hkdf": { + "expanded_key": "40D0E2FF3CC0401794857BA46D4018D6", + "v0_identity_token": "2D00EC3B8F0F5E82C0FDF2ABEFE0" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "DE54", + "short_salt_nonce": "FCF5569BBB730792EAC492EB" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "24921B2F2ADDC07DE0E4818DF0FA218D", - "legacy_metadata_key": "F36505BC7D272E0A61E6F825CBCD" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "FDBF480AFE38C1A3B518C9E4E37DF73B", + "derived_salt_nonce": "D0AB883D19A80B9A9B0F71FCB3BA9C4D", + "derived_salt_third_de": "559EF43087D81A97644A1564939C902D", + "section_extended_salt": "7D6E587DCCB086EE382CDA8ECA378555" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "A188BBEE6CBAB5C972EE985C21ABF21E", - "derived_salt_first_section_no_de": "5170EA5075FD2D3346430FE8781E352C", - "derived_salt_first_section_third_de": "A7280620B2E6907C765DB1B005C56485", - "section_salt": "C362D9DEEAB32835AADB2713E86AA3BE" + "key_seed_hkdf": { + "key_seed": "CE5928B1C8F46246E5C922C80DD9558FA8AF4F213E21AFB8A99B0FEAEB9B56DB", + "v0_identity_token_hmac_key": "0899E9BB8C98AFAA6AC98097F66B0342806FDD2B90676D2C20107CD6947BD3AD", + "v0_ldt_key": "4134C4E3F15361F79134E2FCF5ECB398EE7E4ECB43A839622859BA72CAF476732ECD67EE3B354236EB64ADD7C0D2E0CCAB5E051D12792F39B8846616BF4A84DE", + "v0_metadata_nonce": "8566A1CC7A91F6A022B999E5", + "v1_metadata_nonce": "396A0AA737EA6C93E27FE7DA", + "v1_mic_extended_salt_aes_key": "800E76656036F4A04879808F114BAE67", + "v1_mic_extended_salt_identity_token_hmac_key": "FE24751061A9F50086411F85352EFF5B5DF0E1247998A203B33CC609EB63AB50", + "v1_mic_extended_salt_mic_hmac_key": "F095007E76CB193DA11718890BE7D735C9B57DD99C85E597893E9A51DD15A93E", + "v1_mic_short_salt_aes_key": "52A881282D67F6ADE798591223985FF8", + "v1_mic_short_salt_identity_token_hmac_key": "60CDFB8EDEB884516A7A3D8501E3357AFD42A77CD5FE6578D2F5957FDA03F5CB", + "v1_mic_short_salt_mic_hmac_key": "8555D441A574D3375E50F9A450022F4A982E8D580982908C7B6D81C628312968", + "v1_signature_identity_token_hmac_key": "E850671925AB258049D3E3A4822FD1C78A4D80F556FB92EB7D7B5DA01F5CE641", + "v1_signature_section_aes_key": "8A1ACA177E160A79924EB4D2C9435F98" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "AFB1", + "expanded_salt": "6D35C770B1F09DC2DEE7453C22EC018C" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "BD6393FDA5A002CF968AD7F9", - "extended_signed_metadata_key_hmac_key": "6CAFF8DE3681C4445926AF1CB615B8A7EA39687BD24597384002F0EF1BFE7FC2", - "extended_signed_section_aes_key": "03A107EEEDE319EC3C14B287533F26F9", - "extended_unsigned_metadata_key_hmac_key": "48107D08007213F545238626291ADF3963F71D64A7E42D859B77F5B5FED3DEDB", - "extended_unsigned_section_aes_key": "918832BE7D5E3E5DCB8D6FFCFC53324C", - "extended_unsigned_section_mic_hmac_key": "A0E2D0EE71984DD82D3AC1BDDD030913D4BC9BD276E71E2BEDB57290B0AD652B", - "key_seed": "7B1FB28E5884B2B7DEEDC2620A87E729C1AA5E3810C56F59FAAE375BA22750D8", - "legacy_ldt_key": "00A9B6FD99AF13743AA3B6E31381E4321EF15F21D4DF1D8B904307896ABB7ACE185526619BDE388E462847F178F32439245D8A4AD45AA26759DAFB751B6BB544", - "legacy_metadata_key_hmac_key": "27F5E15D51C393501B5C9AC3254A8FADDE756110C8E8A952DE2FD58AB3EFD16A", - "legacy_metadata_nonce": "DEC66637548279AB556A1219" + "v0_identity_token_hkdf": { + "expanded_key": "23A208FB72F76B27842D0EF4590681EF", + "v0_identity_token": "3080D30C82A0F6AB7A5FA83675C0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "781C", - "expanded_salt": "28C257CC0BDEFCDC63D28B14D38A5E9B" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "96AC", + "short_salt_nonce": "9BF830CCD7DB20F7A3115702" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "DD89372C6BC8038EF866314AE0015DBB", - "legacy_metadata_key": "D0D0C08326310877A07002234539" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "668E2A14D9B304AC23D0F56CDFE0726A", + "derived_salt_nonce": "866E7A3B3D3F0A094F8FF58C221754BE", + "derived_salt_third_de": "137E0CE6D82B8DE9AFDFBE0DEB447B33", + "section_extended_salt": "4AC4230A5F3B911F69A07DCE728586E4" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "425882E16247B61965C2CB122571CFCF", - "derived_salt_first_section_no_de": "0C8429B057889FF103029651B0178DB1", - "derived_salt_first_section_third_de": "61F70C6EA361790E715295EB500A9DF6", - "section_salt": "2BE5976B6054DC8EC9B517B03FA25754" + "key_seed_hkdf": { + "key_seed": "A036E6CC7FC866CA0BE5B4C017CF177396E403F7D5CA8F94C6FF9DA7C010299C", + "v0_identity_token_hmac_key": "D85A9EF927E02B5A0ECEF8B1949846AEC6D7FFD049A465288F8BE406E63EEBEB", + "v0_ldt_key": "C95083F599D7D994F72142C844822652EC9C914F132AFB2CDA4C7BA88B4235A76CA1BC44FD42CAFFAA7A553BB74E93F30E4E873DD1348F99D0125577D06274F8", + "v0_metadata_nonce": "23D7F03405EED43619F8A02B", + "v1_metadata_nonce": "ADB6676920779A3F6D24F542", + "v1_mic_extended_salt_aes_key": "B3A11A9DDB232EC9634B28EB5DD002D7", + "v1_mic_extended_salt_identity_token_hmac_key": "E9E49F8A8FE50E066C83BAF02D9277BBAC5EC629D16FD5B02F90E04EF76E682E", + "v1_mic_extended_salt_mic_hmac_key": "0E5A3BCD461378A07659FBBD5E22AD8A658D3871FDA1B94111F5F468298A8D74", + "v1_mic_short_salt_aes_key": "C3B2251C9ECEBABBF766D5185B5F18AB", + "v1_mic_short_salt_identity_token_hmac_key": "ADF35872686CF343B3CCAC85D02789B9AE1F9D30A8DDCFF90EB87B17232F928C", + "v1_mic_short_salt_mic_hmac_key": "EE54C5BB9C1BFE150A389B0A87E4181694721FA52C7DFAD2012375D95356CDCF", + "v1_signature_identity_token_hmac_key": "D1E4984F45D313CD9FFBC84344861B3E4695CD514BED3150C16533E8D342CDE1", + "v1_signature_section_aes_key": "15EB95365271D866D98BD422014205B1" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "9BCE", + "expanded_salt": "CAB8E837BB60A1FDF5F164F1930B0E8D" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "22E652B9D05090C3CD17A386", - "extended_signed_metadata_key_hmac_key": "B1F52377B751B3CD5456DF79607FF00F47388F2063BE559A151B7B9985030D9A", - "extended_signed_section_aes_key": "6C6A2C0C4FB7B10E71D4B9C90DCF97D4", - "extended_unsigned_metadata_key_hmac_key": "AE15A2095E41AFC7E33ED5A4F1210E36BC8B08761DCA1A50C8AAAF4D18804096", - "extended_unsigned_section_aes_key": "FF93EDCD2458BD330CB8F6461CB5F3FE", - "extended_unsigned_section_mic_hmac_key": "2ED5F7C30A3EBF854A6EC62863D9C22CA14BB8B3EE34C2E4CA48AA1972E6D74D", - "key_seed": "674EAC48402573CBF8D9C71F862F2F773330F1C8777B86D6C1C054DCBDD7F5BF", - "legacy_ldt_key": "C98FED8E0671B3B73E31019FACA33127F2EAE11BBC8D6D503E7C4C36DCDF42F8711EAFAD6E64AE2EDB6D2870203B64EF74388AA0FDFDEC9372AE06E4B14639BD", - "legacy_metadata_key_hmac_key": "C39A23027BA99068BB113712449125BE8B4E891C92B9B822EF14FEEFF64D01F3", - "legacy_metadata_nonce": "03759271308F135FCD00566D" + "v0_identity_token_hkdf": { + "expanded_key": "42C1EF92D5E71149BCCC7B3B2237410F", + "v0_identity_token": "C3B8624C9BA609C1BDCEA9CF373C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "F14E", - "expanded_salt": "1F35B6CAACCB4DABC88F014F186FD58A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8466", + "short_salt_nonce": "AEFEF9A66BCC84F652A6B6F8" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "4DBA128B48257E51906815A44EBB31C8", - "legacy_metadata_key": "1BCB5E77E87246FB145B53599415" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "62CA3E3C25D90BC9601B292D3DBAF36B", + "derived_salt_nonce": "DDFA02449C05C95B5D958B876CA189DE", + "derived_salt_third_de": "40EAA779A52CE6249681C6C2A6E33839", + "section_extended_salt": "9054B345A1B790A68CFF7CFC52D75525" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C210EEC7E5F37ED5DD585CA78E4F461C", - "derived_salt_first_section_no_de": "512F88EC4D2C1D98155A79C50766881E", - "derived_salt_first_section_third_de": "5C51EAFD14CCB470D455818FC233951D", - "section_salt": "1F6F7DCED1EAB1B9AC53C24BF29D9E74" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "6EAE4DC82AB5941A1E09FEF9", - "extended_signed_metadata_key_hmac_key": "8646A00AC8922FCCC259807B3B9EAEC556701927DC03ACADCB1DE1517F2C6C3B", - "extended_signed_section_aes_key": "DA63146BE1A81A806C6DFADB9076E6C8", - "extended_unsigned_metadata_key_hmac_key": "2F437D2C9BD771D02A87C0E17CB053958F62DC13559413C871FC01B4E5FB496E", - "extended_unsigned_section_aes_key": "9366D940C998995D7846B28F0FCA05E1", - "extended_unsigned_section_mic_hmac_key": "092BC3A92351F4673A37BFEC4BC62F8FA042EE9E5ACF391B2668142015570658", - "key_seed": "6028F5FEE8F66DC80D4F1C4155D7DCF9495C4D98DD481AB2BC30C9FDF0672A2E", - "legacy_ldt_key": "AC718CAC29033FF1FF300BC44B99BFD97F5419AE42BD79837E19D52C115C01FE32F0B2AA678D756B088BDD276CF6402B729A69F2689FFF6A035B5C9B6363A49C", - "legacy_metadata_key_hmac_key": "B0A90F0DBC1ABA5AEE0F4A8CABD5764EBC83F3BD618656BDA509E594A91E4D52", - "legacy_metadata_nonce": "4788CA94F7A0AB258486D3F7" + "key_seed": "71B63EB56B07CBC9322E666347CEA44BC4FC6344696D7D5F879E2B2538C6C0DA", + "v0_identity_token_hmac_key": "CD3092A8E4B648FD3DC6C80A449FB248F05934A116A775F6C70A9D5FD07E5A0F", + "v0_ldt_key": "3C2138F65AC20985A4BC677B4CF36F9D09B316E25506AAFFC407E2B72468B6BC71961D5958D4846793392C7389053BB7C248BC6E47269E9619098FB55D38E254", + "v0_metadata_nonce": "459816206C609FE86EBA6D7F", + "v1_metadata_nonce": "14B7E15A016D8BC3849BDE28", + "v1_mic_extended_salt_aes_key": "C6B3C93BB0063BB443EB0A4AC6EE4BF8", + "v1_mic_extended_salt_identity_token_hmac_key": "0D189A29519293EA6995D6658527ADEDF51CFDD500F4E602BEDC242740308898", + "v1_mic_extended_salt_mic_hmac_key": "2D65B2CD24E315B3B60237770E5F14AEE994E718C023B32BBAE93F00A49160CE", + "v1_mic_short_salt_aes_key": "C886A50B76F6FA70D653F47D58E32DB5", + "v1_mic_short_salt_identity_token_hmac_key": "73D1231C70DF32D46609A2BCC11E0F1C09298F772ED3C1ED61F3473F6B0D109E", + "v1_mic_short_salt_mic_hmac_key": "8BA22F5A56E0C7D945A43286C432875B2A8BA4D340B71FDB32A5078BACF81D05", + "v1_signature_identity_token_hmac_key": "8F3E043B38AD640DDB32F836B000FEB140E293FEFFE22B048DABCC6AD0D77EB8", + "v1_signature_section_aes_key": "F0B1C0499D7F735D789BF19C6B27BDA0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "18BD", - "expanded_salt": "1702E72B0270FAB301ECFAE901FEB45F" + "v0_adv_salt_hkdf": { + "adv_salt": "02DD", + "expanded_salt": "0559A2DDCA64BD2AC3BFB68B58D8D33C" + }, + "v0_identity_token_hkdf": { + "expanded_key": "64E3B4DD353BD25E6A6DB0C693D3A38C", + "v0_identity_token": "615B490B1C2BD88CB66FDB5020B0" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "C0A1", + "short_salt_nonce": "FC5A9CD5C30AE35F2439A989" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "ED1208D4B3435736B92075B4E2DFBA3D", - "legacy_metadata_key": "AF7F068F3FD3FEF1B9ECA66F33A0" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "C7C542850D51FC65A3748B637D4BF2B6", + "derived_salt_nonce": "E7BC6A195FD35BBBBD36890C84DFD6BF", + "derived_salt_third_de": "08B163B3C00BCF2302E50BCD54DE256C", + "section_extended_salt": "B045F1FC3AA558F7DB3436B43FE3703D" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "B27EF32036E2AD671536F7CDFCF3D8D4", - "derived_salt_first_section_no_de": "3841B50190E59B72F7F47281ED980317", - "derived_salt_first_section_third_de": "1658D434AD2BD8190467E009476C1F7B", - "section_salt": "F9172022012C774D058C8383D2D4235F" + "key_seed_hkdf": { + "key_seed": "4E0E7EA2FD1505C0917AF77650AF066B4CA785C71E94EADFF9179A700B871B99", + "v0_identity_token_hmac_key": "F03B77CA61C2E4F3CAFEB1ACC40A5B6EC7DC91E4EA5A453603A31C7C15398FDD", + "v0_ldt_key": "E2F5B9301BDB44BDFDDEF6A186AED98E40E044EE0246823157ED03BEA1BDC2416BA43B7579E762141DB967AA5AE4D3A7B29E2DE79225CF58976B1D0A848253F9", + "v0_metadata_nonce": "E40E15488FD763B95BE80EEA", + "v1_metadata_nonce": "E27F419A42791059D8ECD258", + "v1_mic_extended_salt_aes_key": "DA459644331D2AB5BBFA36F4D7FF3C3C", + "v1_mic_extended_salt_identity_token_hmac_key": "9435C376887ED2BDBE06AE6E216B20F3A5F513D5C73CF7A464FB00C96AF42156", + "v1_mic_extended_salt_mic_hmac_key": "EBA1ADD68E7A7175C6EA4BAC7C9DA02408DA8B42B079CE25883E286BE7D027F0", + "v1_mic_short_salt_aes_key": "B4FBAAC9FB28B31447917346BF960A6A", + "v1_mic_short_salt_identity_token_hmac_key": "8261D61215141838D5F9BE7B561917B4BE89A7CD558403E146FD5F9FDB232308", + "v1_mic_short_salt_mic_hmac_key": "776E5708C049603DE6CD23D46F5867BD4CFCBD68865DA033F76284C02248C5FE", + "v1_signature_identity_token_hmac_key": "8A10585EE8E9DE84E26A0284C4C0AADD7726DC54FCE6FB2196C6314661B8D765", + "v1_signature_section_aes_key": "1324A78CBC23F567A880B1975F0ED40C" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "10EE", + "expanded_salt": "FD6A9A6E112D7D76ADDC2D8BD40B7E29" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "F7BFDC47005FE9892DD1A940", - "extended_signed_metadata_key_hmac_key": "9864300E87DD5F34284AA47C00381B36C69813423B6BFCB14250715BAFF34259", - "extended_signed_section_aes_key": "93C04B6BA7CF6F4A9B27615C900086B0", - "extended_unsigned_metadata_key_hmac_key": "4CF4F78468301DC365A2C27BF4D544CE525F3CACDB471868FFCFF896D896155C", - "extended_unsigned_section_aes_key": "908CC6D593CD9401D47CB850BF4812F9", - "extended_unsigned_section_mic_hmac_key": "68283A8DDFC70B5B523E8ADB8DD98C209DD458140E3ED6C61509D4259DA8D4BE", - "key_seed": "F04F58F4C6158F4E05EABEADADC3453F3A75FC3B6D331B45FD5589D0B16D5F1C", - "legacy_ldt_key": "AEC307B3A752EB1C5FDFC64843A93ABF5D2674A9505C736D131B1C84BB89A17D09CAC89BEFB1274B56262CAB56F04EB013A4475B518170C321AF4DFEB3F3CF27", - "legacy_metadata_key_hmac_key": "2C16FE1F32E5077BBB9C659C55BD9A77600FCA5D45FCE0430127514E513973A5", - "legacy_metadata_nonce": "628F79EC288BDD800A4ED6BF" + "v0_identity_token_hkdf": { + "expanded_key": "A0879258EB4E46C9AD228B720035C301", + "v0_identity_token": "2CBAAAF3C96B0F18CDB02D332249" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "94A0", - "expanded_salt": "9201A2F2DAB3488533230CD580588267" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "61F0", + "short_salt_nonce": "615C3235852E9D1CD0063CE4" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "735ACB0A5B5A47743F22EAAD1F64F8BB", - "legacy_metadata_key": "1DD0B9A032ADAB96501E851CD707" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "6272F7C2A41C3A15288E20DF6298EAD9", + "derived_salt_nonce": "E2F217DE0828333D9F49E122636431EA", + "derived_salt_third_de": "74DF8645F7FFB751482B84D2B291D3DA", + "section_extended_salt": "189063CFAF8E1915CCF88CB306E65B16" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "64C97FC6CB9A499116614733309E473D", - "derived_salt_first_section_no_de": "3B2B9FCD5DEAEE859EFE8B7C2C8FF150", - "derived_salt_first_section_third_de": "38999F9FDE0BB4A02621675A265C0F53", - "section_salt": "E152E9CA82C846268793A13AC2CFEE01" + "key_seed_hkdf": { + "key_seed": "0C4BF3FFE9CB060E30C97ADD9DC99E4AA2E6EB6AEC723BF8BDAD409051D3BD37", + "v0_identity_token_hmac_key": "ABFB8A91549E636D07DFB7E57A817C9C2891AA6E626E38A3EE063248CE912F86", + "v0_ldt_key": "93A179BDCCA21151352CEF07195B0D8F8B7018E75078A0E1B99F7E4A0D239CC08059CA82EF69848E5E3894885A4EA80B7B664005BC6C1EAE6B93094FFD2129BF", + "v0_metadata_nonce": "78FF83DFB55958CAC1F5983C", + "v1_metadata_nonce": "7FB9A6EDE0C5D91DF8E567A7", + "v1_mic_extended_salt_aes_key": "090D4308933E3CECCC986F09A37CF87F", + "v1_mic_extended_salt_identity_token_hmac_key": "5A8BC4F150492B66307B1DDB38AE19E594AAA280FEC8EC9E79F4B1E3DEFFA525", + "v1_mic_extended_salt_mic_hmac_key": "1F8DCC645A797A805CF72D23FD6DCF3243735737BE0E11870614BD547C56D3D7", + "v1_mic_short_salt_aes_key": "E49F8D00B07699825E9F82D7A668F8D3", + "v1_mic_short_salt_identity_token_hmac_key": "9AFBB83B9CE4C2A0A1F865B4386E87BB31273D46BC1F5C272D1F2F098F46C579", + "v1_mic_short_salt_mic_hmac_key": "A68EDA18BF3D5CE9CFB3EEC57922F0E4EE0DA69C36F353C9302976ACA66CEF6E", + "v1_signature_identity_token_hmac_key": "55602CC889D8C5B0C8E2F37149831B6C97DB377B2168A8A06BC667C8D017AA29", + "v1_signature_section_aes_key": "9EC0098FC8386B2260A44033CAF969FF" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "FAF0", + "expanded_salt": "349DD2805CAD12CBD795101D47403486" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "0FAE226D0C037417DF2CC8F1", - "extended_signed_metadata_key_hmac_key": "B03AF5D25B64EA34DEA4A04B30E234D0C45D0844AD3D76E9D4BDF72B9E1634EF", - "extended_signed_section_aes_key": "419A9B17073BB3A7DEA566D14B322675", - "extended_unsigned_metadata_key_hmac_key": "8CD58449D0AF3398E3649F977A8FBC55573464F4E25818E8ED94230A270E5B42", - "extended_unsigned_section_aes_key": "52CFA465829A0AF17FCD496C302E7094", - "extended_unsigned_section_mic_hmac_key": "B098BCE7ECBE5DC667C7DCD99B186B3294C442783741A2AF02973B9C1CEC3E7A", - "key_seed": "26005EBE2B54878D7D51E8AE0A133F601F845706CFFE22EF5406E848D743CDBD", - "legacy_ldt_key": "86F94EB0B3514972F54E4B072694BE295FACB1C9B1CFFEC97F7AEEE7E7A4B2EEF8D83CF3F46A1046553F0FBA739B512BEB70E8294AB3A8E9D354DC15904F8FE4", - "legacy_metadata_key_hmac_key": "6C5F27B8758F150413A0E723AD2C87A89FC8E0922D6AFC9C4BEE7D640564F20E", - "legacy_metadata_nonce": "C9E22F8D09D4F4593A61FE7C" + "v0_identity_token_hkdf": { + "expanded_key": "901F6D216BEBF74D2D0E46E033634FBE", + "v0_identity_token": "B297A12E68BF33DB8ADA62316B4F" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "35EE", - "expanded_salt": "6DD6FC15DC3871D1664A44C78A886FC4" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "44F8", + "short_salt_nonce": "BA72171618BC1AE229E46B79" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D1B46D2631F70EEDEB29AA47D4437686", - "legacy_metadata_key": "1416021C29E743088B02B41B571E" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F3B0AFF9A87AD9F157FCB595A0400440", + "derived_salt_nonce": "58B7445E6B36BA40A10BA36B5C1E2EE2", + "derived_salt_third_de": "087236B6E0C93C6153A061CE6A145D2A", + "section_extended_salt": "E574B5E9485189F792010872C55A1A16" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "9651CD6607E54363129153CA5315FB86", - "derived_salt_first_section_no_de": "0A54495999A555463622F3875F8B0589", - "derived_salt_first_section_third_de": "E47744FCFD5DC037621555A11E000988", - "section_salt": "5EECCF54ED89546D031A0103EDB17A2E" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "57F6D756297E1693FB8A1D4A", - "extended_signed_metadata_key_hmac_key": "1A7B18552F2818F7B17106C0D32337D33F69903604CFA6807DA5DCF2746108E3", - "extended_signed_section_aes_key": "194961312A320FBF060414DB8650ED9A", - "extended_unsigned_metadata_key_hmac_key": "25B117B4EE587290C4F7CEC17115E104FF96E7EFED13033C1DD4705BAFF3694A", - "extended_unsigned_section_aes_key": "B5E64E57E00D022C4A1ED7F1841B5A1D", - "extended_unsigned_section_mic_hmac_key": "D499BB4DA43B7ECCB3499AC1B5B0E251AEC407EBCA917F0EB08838BD618476DD", - "key_seed": "D3457A18BF634AD2166223C38B4A1BD74C66DCCE809D410CAD1218F56EA363D4", - "legacy_ldt_key": "D32BB668B2AA256B27339F45F228672FD51BCD73C3C0C044E9A9E27E282D867BF2A7ABDE2300452BDBE49B79C3457F65F38186A59D9B88FD5164365212DAB6C6", - "legacy_metadata_key_hmac_key": "10A19D2EEA33F510D969E3A7036D1F288079A6D242EA2B1376DBEBB02F49C503", - "legacy_metadata_nonce": "CA9A9DBF70527FBBDD94E59D" + "key_seed": "ECE5B0557E2B77C7267F12D916A058AE7A989E2EB7E3DDA012EE4615DA3E072B", + "v0_identity_token_hmac_key": "51A45AC67195344FA0FF0F6B45A555E0113EF7A976E1371C38ABC1092A739AA4", + "v0_ldt_key": "0C857A8818273B2087858DC361082FD28F1A526DC3C8C17524294AE9C4B4369FE678F3D1ACF4AAFC6D2CAAF5E9E20EFBB5CBB6E4D42BBA520D244762E3569B15", + "v0_metadata_nonce": "2397ED85E3AA65D707364D55", + "v1_metadata_nonce": "81FE5070C63D916C065E8960", + "v1_mic_extended_salt_aes_key": "02F8434EA7ED25A95997308A704DBEAF", + "v1_mic_extended_salt_identity_token_hmac_key": "DC250FE0C182459E9502568122871806C76721D8EC15EA858823C6943A22FAF1", + "v1_mic_extended_salt_mic_hmac_key": "C073CA0A8FBFA53DE6D573FF2C4DC981C8567DCD41674F666A9B6F2A3E5DDBB8", + "v1_mic_short_salt_aes_key": "3CA3A347F198B2771543DFDA16EBF066", + "v1_mic_short_salt_identity_token_hmac_key": "526F4A2BADF226817B6CFBECAC622C76ECB29F08D94E76A19E0E5AA47E60BCC6", + "v1_mic_short_salt_mic_hmac_key": "B1BFA6EB1CF610F7ABAB39846A4096A201400C96FF365FA28DC17E21A10B4843", + "v1_signature_identity_token_hmac_key": "CDB40BBD6E8C6F09EACB8C49F6620036AF9EDADBE2C4DDDF4F1576BD16E60D97", + "v1_signature_section_aes_key": "89D7606A0A0A3BD01ECC6C5753B73976" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "00CA", - "expanded_salt": "B2D541DDC7E007FD5D9B394E66C33319" + "v0_adv_salt_hkdf": { + "adv_salt": "9F8F", + "expanded_salt": "C440F5F693A391089F493578A3246EE4" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "0A4F31037E77231B0B51C8A447E3E329", - "legacy_metadata_key": "03E5B8D922677CE5DC011BAFFBEF" + "v0_identity_token_hkdf": { + "expanded_key": "08286E0B99391DA30EC2274DBB00E849", + "v0_identity_token": "D00DCF154C31C752B929FAF666BD" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "E02D", + "short_salt_nonce": "622C675E322ED508F3D36C63" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "18DACA43407EBFAC3F779E06A67455F9", + "derived_salt_nonce": "F82E736F62D198165C6D347EA4E39C6E", + "derived_salt_third_de": "23619B13FF4E31FCACFD529756674E09", + "section_extended_salt": "BEE23DC5EBEB75C788B766ACEFA64377" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "9B1DCFE8149C1EBD905A5F2B71341C05", - "derived_salt_first_section_no_de": "BEF89573FEA45BEE4E9BF988824904F6", - "derived_salt_first_section_third_de": "41E32C74EDC315E7929DDA7FBC91CC8E", - "section_salt": "EBF3C70C17A01679A563A39FA46D7F0C" + "key_seed_hkdf": { + "key_seed": "9E694C7731B4C8C077DE1E5233B3F6E8E47E436D920D8C4E4BEA39FEF681978E", + "v0_identity_token_hmac_key": "1A6329E5D9948D1DA2B988FF7A1A703222A085894926BD27AA92BCFF19563469", + "v0_ldt_key": "D79115F0BBD9AD968C1F99C08A1F6EE03997499BD1549F66CD1603B40B18FE15CB61057F6ACFFE7DF23628AA5D7A7E6A1AB3022ED735A0EEA7B025FC16897D6B", + "v0_metadata_nonce": "60D20D161EE6B97FCEE5E2DD", + "v1_metadata_nonce": "42876252FC40CC971CD39A6E", + "v1_mic_extended_salt_aes_key": "584DD6D94E5DB46E5EDC4BE2B854368C", + "v1_mic_extended_salt_identity_token_hmac_key": "0E71CD49557CD6C9CD914B1624E2880188F8ABDB142E546C4D04570FA606E3AD", + "v1_mic_extended_salt_mic_hmac_key": "07863900E27135BC852442C80BFCBA09FE418A460F91DCF30F88F194F2B15DE5", + "v1_mic_short_salt_aes_key": "E0DA5AA00A18AB165C15005E75A02F7E", + "v1_mic_short_salt_identity_token_hmac_key": "C6870BECE7AC586F61563E3FA8F460728218E93644B40E0DDDC621A01042FCC0", + "v1_mic_short_salt_mic_hmac_key": "CCBA93DACA9023B7633E5408DAD5EFF1FBE3A00E9F76E9AC8507DE5E651A5FD4", + "v1_signature_identity_token_hmac_key": "E6A09F1A28C2DE26841044AAAC67C4CEDF963992767C960796E204BBA6B61432", + "v1_signature_section_aes_key": "F610CCD8C43EF4D6E738CCD0C1C24C09" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "605D86FAD007BC4EA0878430", - "extended_signed_metadata_key_hmac_key": "EBA52456957CA17961D098C55159D6D79C3451E5738468586D4187B15300ED2D", - "extended_signed_section_aes_key": "76FD6B925AA863C06D42FBEC0F29B98C", - "extended_unsigned_metadata_key_hmac_key": "C80E7E9DE0E1357E95AEBABEA46C14C4065D8FB1B4B4CF755413B3F5EBD930C7", - "extended_unsigned_section_aes_key": "AF6EB46E7DE399B15CBBB1F54BA7436A", - "extended_unsigned_section_mic_hmac_key": "0F3EB356450F0A6C99BCBA4D69899631CCB0E18D5CAAFBF844D61B741EA44E9C", - "key_seed": "3652F27504B90685287D9F9EFC800244A4F250F153B825F00389A5578D50F9D5", - "legacy_ldt_key": "656543A5C4CA235799BFA3EDEF3734AA57830F3EB0D4BC94BC42A9E4265D0DA8838B9E69414F07E0F933784DD054194E660F604F345EFBCD694C2F466499747F", - "legacy_metadata_key_hmac_key": "836A63241862CFE7B29FD00B05A9438D293E05E460C0E77C56804461803DCCDA", - "legacy_metadata_nonce": "E188B583B00F2910B16EF19F" + "v0_adv_salt_hkdf": { + "adv_salt": "1B22", + "expanded_salt": "95D2C439CAE94171D8F64ECC4D79CED2" + }, + "v0_identity_token_hkdf": { + "expanded_key": "D5D6FD18F488483BED09863555AD3BA3", + "v0_identity_token": "3C7E4793630A8229E8D7E2337E04" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "E5D8", - "expanded_salt": "FBEED7B8E11129FBB42F282F988B1A81" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B898", + "short_salt_nonce": "D983D29159D24108F06DB7D3" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "95124B323D4373E93FD74091B97406D6", - "legacy_metadata_key": "CE875009453430A68CDB21A04D5F" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "67BC64977B228888CC5CD6466E3112A2", + "derived_salt_nonce": "44279BC1027CA9D501947166840CF2AE", + "derived_salt_third_de": "D656A3294C7E089F94ACF3FDFE93D463", + "section_extended_salt": "D482C2A6D420C5F6993527865FD38E45" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "A04BF6A2FF522EFB9682A288C93BB656", - "derived_salt_first_section_no_de": "57DC6F81CE5B7432540EB145659C56D1", - "derived_salt_first_section_third_de": "769504709A8FCC5EAC8927039CE9DA64", - "section_salt": "B10E4B3856910D59B98435355E69AB25" + "key_seed_hkdf": { + "key_seed": "CE2C5489AE9BBD4E63911BB5D51B8EDC726A6F30557C012A8DD37206DCC4DA0B", + "v0_identity_token_hmac_key": "8BCA9E29B97BD9610DFBEB35DF02261C16A3A6E7AF8EE60C45E7A8EC00057F6A", + "v0_ldt_key": "51A6880BFA961E52F8961CD397D3905AB3EF02B6431394390C330CB0480AEF3B48F6D02CCB8E7496985B802F13254AE6747E5AE585C8D0D390E81A17406199C0", + "v0_metadata_nonce": "0AACCDF41FBF33135BFE11E8", + "v1_metadata_nonce": "04411E15C45DB0FB941F1B09", + "v1_mic_extended_salt_aes_key": "31E9CF730E31A1A56C75624790869DC6", + "v1_mic_extended_salt_identity_token_hmac_key": "400E94EEFE9F40AC2761E04EF84D4C9A5506AF2BCA87F1FFC3C41DB0CE42EF6F", + "v1_mic_extended_salt_mic_hmac_key": "35AC887D2973BF40F73476F789E095A220919AF1C4A308A20C4B72957A6F0847", + "v1_mic_short_salt_aes_key": "18A8B80F7FFE5B3818837D04BAF23FC8", + "v1_mic_short_salt_identity_token_hmac_key": "5CD8B34230B6BDED50B42E1EAF30F46136432AA2599F66A4F7AEE7442E974BA5", + "v1_mic_short_salt_mic_hmac_key": "91AC6D599B6D5EDDF95472D946A8C60292896C395DF3216FE6B0297BF0FBC890", + "v1_signature_identity_token_hmac_key": "848F82B20E686C242A2D7F1933E0CD872DBBDF1E7B436856F19424BD47078DD3", + "v1_signature_section_aes_key": "7A88551E0D0B4C248BD88C7214423C1F" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "C0FC2A8AD5C0AD828ACD91F5", - "extended_signed_metadata_key_hmac_key": "720F677655EB635563DE99FA07E045D7074C1E099401341E7A7A3C93B55BAD55", - "extended_signed_section_aes_key": "BDE744442E32EBA45FCC5C6340342AE9", - "extended_unsigned_metadata_key_hmac_key": "1B380539C060707E986587B52E0EFB9EBC7907F939467741D385A3A706137078", - "extended_unsigned_section_aes_key": "AD4E22885C75C1767DDD55943AA675C9", - "extended_unsigned_section_mic_hmac_key": "3D1170B39B5766B83A74425A1CECFDD73786EDBDC4943C1063D29609AA6281DF", - "key_seed": "E05713CE94A34C790D245E5340F0034B7FCE8C470639AACFB649E351C4517996", - "legacy_ldt_key": "B77B168EB6924B7DAF554027BF77FEC4C5B0D5FFD370AA0D8A2D6AC2BAB0C678DF858B7B28A143BB4AD12E7D9CAD3B51D939E23C0AE1289797078334530D8BAE", - "legacy_metadata_key_hmac_key": "B564B6695F774376499A95B28B11591EFBDD492948B9840B7207949154A46510", - "legacy_metadata_nonce": "4DDA74813EC3FDD85ECF79A6" + "v0_adv_salt_hkdf": { + "adv_salt": "7DAA", + "expanded_salt": "8B186389B95F08E844499318AF2CC0B0" + }, + "v0_identity_token_hkdf": { + "expanded_key": "558D0863258D8230FD3C931CD2EDBF7A", + "v0_identity_token": "2713C2F2B47DFA957381C10C2649" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "F388", - "expanded_salt": "8967E476B2B0068E17A1B71FCFCBDFF1" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "A20B", + "short_salt_nonce": "412810F614DD5448E7BA6171" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "E36AFC309B6E668C2C3A0CE5FAC3DBD3", - "legacy_metadata_key": "8A97CFB9BF30ECCFA0EFD7E11022" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F613A207D445ED2EC7CBE2A5787EFE60", + "derived_salt_nonce": "92A3862125E69F44E8E6087DD72828B6", + "derived_salt_third_de": "54C805F3DE7A3652271EBD5E097A9D95", + "section_extended_salt": "8D5F11C001A419648067D4A1966B0EED" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D5B0B8A104592ED2AA6605FAD6E2B786", - "derived_salt_first_section_no_de": "546BD228DA5EC1C6706BBD0B6512260F", - "derived_salt_first_section_third_de": "D9093EABE9731CFE5CD5EDC03B3593B7", - "section_salt": "625AC46C5387C640952FD435DCE7BF8F" + "key_seed_hkdf": { + "key_seed": "C79A63177DA5F9CABC80DA27464F9407A50F686B9253CD8D6CE16A2FAAD90DC3", + "v0_identity_token_hmac_key": "154DA7DA9EDCA6AB3B336D1BBF3A3DFC2B959C76BB3DC530DC336469A22EE49A", + "v0_ldt_key": "AA7A2CD44C71098E3F94A8B0155650502F257681BDC8B856C7B2AF5B1136D96F86089FF3719296C183DF56484D0A688308536BE2EEF9FC667E15BDC4D3BB0279", + "v0_metadata_nonce": "2FB6567C04443950D5F10C82", + "v1_metadata_nonce": "A847F747EFE0FA2F8596B2BD", + "v1_mic_extended_salt_aes_key": "855D9EB68E68D7AAEB46C71C66FC1BC0", + "v1_mic_extended_salt_identity_token_hmac_key": "4FDCB83D8EF4C5AACFF25300FADB3816408CF671D9874FC3CAFD8ED6755B3C0B", + "v1_mic_extended_salt_mic_hmac_key": "CD6FA52AA997B94740B8645D647103C671B5795BC46F1E12B7AEFC7067641D96", + "v1_mic_short_salt_aes_key": "6B695E1C8FB3DFDF4C1964B4B3424A03", + "v1_mic_short_salt_identity_token_hmac_key": "900252ED6385B4E457CE563A5E5FC4BD39784EA4BC64958349E7CD427A68493C", + "v1_mic_short_salt_mic_hmac_key": "72DDECC2AB00222B3C70A9B343664B901614F01CD2E7033934DEC4077D6EC14B", + "v1_signature_identity_token_hmac_key": "05CB39213C947B9C4D82F311372A1780E4BB4AFE8480747841B0A681FF092A0D", + "v1_signature_section_aes_key": "E130CCBF8595EEFA23A6925AAD6E394C" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "C2FA", + "expanded_salt": "5B94F9CB6A7867A0D27C9CBDF4B0EA73" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "256918D6714CA183AEA76E3A", - "extended_signed_metadata_key_hmac_key": "44E27B5CF5EB7F40E301D513BFCC0E7AD1D064268ECED1C93E08521C2DA9CDAB", - "extended_signed_section_aes_key": "C717E7186766C821588610DDA234BD1A", - "extended_unsigned_metadata_key_hmac_key": "5BBC3B99F800486E7D1ABF0998E8553CF827B4CB79D556CFC43954397909EFBA", - "extended_unsigned_section_aes_key": "49E46036FD7EEDF2E316C8E3A2C83E18", - "extended_unsigned_section_mic_hmac_key": "9EF8F3A9C044C579691C59EE221859361ED13B4C588E1576C019CBB83411A0C4", - "key_seed": "E2633861C773DE669266B36268FD535E3B04A5269F5BA3B58DD1B2B2800141AF", - "legacy_ldt_key": "B68B9BFB869949766927D96D8E11A8F7AE6B4D0CE4AD11FFEB56CCDE74B4329315EF8BDE16F5B89B6A05373EBDB09ED7272D20F51ABFABF50C901FF4A5B6D45B", - "legacy_metadata_key_hmac_key": "B20510C6C750BFE0991CA3CD6CA3A6D1132A09CD845BDC3C2E006CFA4243682C", - "legacy_metadata_nonce": "F82A5657110463EB4993D5EE" + "v0_identity_token_hkdf": { + "expanded_key": "7EEAF724D0D00C551EFB2985D1E28519", + "v0_identity_token": "FF3A952F373296C0F260CAADD55D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "98AA", - "expanded_salt": "13661848812A9F40B2C9550857E3ABF4" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "6B11", + "short_salt_nonce": "9DCF2866433ED70F26A6DCE4" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "521F75308E4F3ACBA82DA74134C46309", - "legacy_metadata_key": "4F767CCD14102B29ED949CE30218" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "8882901B8F1F333196F1B78FC5D012C1", + "derived_salt_nonce": "EE7A39E6A119642C002E260A972369EC", + "derived_salt_third_de": "20B064790320BEDAC44CE80C37B4FCC4", + "section_extended_salt": "1E7F5C402A5D4994A8188E52A0AD2D72" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "DE24781BCD7E2BD9F39DBD8EDF8EE2E8", - "derived_salt_first_section_no_de": "647E6F36D4F8529748EC831811ECEE59", - "derived_salt_first_section_third_de": "A755924F3874F3E5661E8AA0F3F62173", - "section_salt": "5A6632D4602C01565447BD6939610E7D" + "key_seed_hkdf": { + "key_seed": "1C745DE11ADD00D3CA19D37B5CAB3D60F5F86659B1848A11D3059872B376BB15", + "v0_identity_token_hmac_key": "E08EA49AC02F69DCAA441DFF1DA7DE2181202DBC15F006244458C2431E4DBF90", + "v0_ldt_key": "2E91782584FF49C855E1B842594481C6DB3496D21E19EE85CC8A1FEA83FB52D68CA22FF441DD68F2EAE28636AB143D3A03392847E766C70737357B2EDAF35D8A", + "v0_metadata_nonce": "36DF9D6DD2D171BAC182D212", + "v1_metadata_nonce": "0AC3126A538404024CBDE6E8", + "v1_mic_extended_salt_aes_key": "7DA766C835B14E1AD6352D8956C0B606", + "v1_mic_extended_salt_identity_token_hmac_key": "3830C1826FF962656DF74B541087104929EA9096D1632516E560208BAFF950A5", + "v1_mic_extended_salt_mic_hmac_key": "A88A2984350349201CBA4531C95928DD34D2536CDC6958D6EB77A992AE1A3815", + "v1_mic_short_salt_aes_key": "ADD9E7D962DD812FBEF7D19E09E5C6E4", + "v1_mic_short_salt_identity_token_hmac_key": "44B9B99CF2B3A3514BF22123387F8D45F2197C71348B8FC3EE885A875AE10451", + "v1_mic_short_salt_mic_hmac_key": "62EAB192B0DD022F91733FB357D7DD912C94EBCB45B91F04AA5C0C9A9E7A85BE", + "v1_signature_identity_token_hmac_key": "A427FEC4ED745D0353E0B24CA11D69CE4FFC5117FA26F906B2ED023AE806B854", + "v1_signature_section_aes_key": "6A4CA8910A38C31640CD06D2045E2D0C" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "0834", + "expanded_salt": "A708695452CF14D8E469B91F26BC7E3C" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "1280F2BF6B120289C45DC96B", - "extended_signed_metadata_key_hmac_key": "6D058C55D5B2CBB0B4BBBD51028C0B973F469A1B8E3DAC59D52A1886D088F125", - "extended_signed_section_aes_key": "37E713DAE40FD31E2F92C329CAAFEBF8", - "extended_unsigned_metadata_key_hmac_key": "1A20B4BFE3EB4EDADE909358ACEBF1C020E9539BA5140BC2EF986EBEEEAB45AE", - "extended_unsigned_section_aes_key": "3F872A127339C6C6C511AA00604C411D", - "extended_unsigned_section_mic_hmac_key": "A837546D57AB36B017645E740D6631016E14E5B16DBF71E058DEC61F5F8AF1A9", - "key_seed": "02FED3D1E3307A9FCE2B11203249FDC09CF979ACD85DF62359860EDCE2DC5507", - "legacy_ldt_key": "B4D501B6B7DD28A54A49E3F57F99C782285B30CD69203E5AF7F838CC4A0380DF6EC89D1D67113E4517C6EE916460017B655F5A4AC373AE8FD68410DF230BB138", - "legacy_metadata_key_hmac_key": "E1707BBBB1337ED59704AF606EA54550074F5B3D5C0310738C04128D634A8558", - "legacy_metadata_nonce": "4DB188779B676BC7B70F234B" + "v0_identity_token_hkdf": { + "expanded_key": "D57B964F7DC6F9BA1061A25550D8693D", + "v0_identity_token": "F3AA301AA094B20B2B0E7A02BB81" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "3B69", - "expanded_salt": "A05E1016967C2E7DA79688AF74615B4F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "766E", + "short_salt_nonce": "FAE06666F8180F410474F3F9" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "FA9ABBC8316622DC2A9843BA0097E0DE", - "legacy_metadata_key": "AE83451CAC8181606BE17AC715C4" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F6BF0314DB3A1C1330A8E6E9A2CE5E7A", + "derived_salt_nonce": "7D5985FCF0EC057383CF3BAC7B113A43", + "derived_salt_third_de": "84F6F682DE9C87BDD9AABFFCDC14A822", + "section_extended_salt": "CEE571EA0F50EC647161523CBC93367E" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "40ECE473568BE946121A394FE60B8737", - "derived_salt_first_section_no_de": "7548394C226D05F10C9B557BD0359040", - "derived_salt_first_section_third_de": "2E8189954D8068F3CB284740CE552CCD", - "section_salt": "B3A517BB5CA6D1627B9A0255B31CFE31" + "key_seed_hkdf": { + "key_seed": "C767661E4DAD8FDF897BA00727A98FEFB87AC252BC0975BFFF3FC4AE3844FA89", + "v0_identity_token_hmac_key": "652640BD7236CFF84A9E87D57775FA4A81F7BEBAE501AF8B64AEDC0C844102E5", + "v0_ldt_key": "3EE26E3AD6244AB6720D572EB4AFA66A6B4F474E911DD9795E9903BBD90B8D2ED94C2F7EE7CDD0D66B9B092D40F0AD1E3EF53D2D959ABA9EDF561A9F7E3AD675", + "v0_metadata_nonce": "4A57C7D89DA48A086131D3C0", + "v1_metadata_nonce": "4746E50ED394092187E13D8B", + "v1_mic_extended_salt_aes_key": "B487D5205DBE5C0CF663BEDA55163823", + "v1_mic_extended_salt_identity_token_hmac_key": "114B6C0BEBA4663ED08D6757606B528F7C3256EF2BE148F7BF75F6DC401BFEF8", + "v1_mic_extended_salt_mic_hmac_key": "BF34BAC8C099EFDD3BF41C051675CDEC259C27786E50CD326FFD409AC8ED6026", + "v1_mic_short_salt_aes_key": "F3482440016A1E6CA2E1C79EF3B9F3B2", + "v1_mic_short_salt_identity_token_hmac_key": "BBB7762E694FF6DC4CA9F31A537094364495BADCCB73FC69327C86D8A84FDBC7", + "v1_mic_short_salt_mic_hmac_key": "E35BD2293E90BD3AC97E98C2983EAA7B7F106AC55B3D88D332539F928CDB8E09", + "v1_signature_identity_token_hmac_key": "7F9ED591367A0EB8A4F23D145BA75249FD5842B59E8CF8C8BB9E69E942E555AF", + "v1_signature_section_aes_key": "955D996A026288A647EA707B0A33C9EB" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "CB9E33EEDAA33993FC4B5318", - "extended_signed_metadata_key_hmac_key": "08AD406C9CCDB3892CFF81B5FDABB9ED3B08A24FFE60FBA487A9DE2EAB871A26", - "extended_signed_section_aes_key": "973BF0F1F7B463EB9A97E1681BD1D3DF", - "extended_unsigned_metadata_key_hmac_key": "E1DABB2A2F8D3CB975196C9BF900491D463BBEE01E408B3E595E718EBD1AA2AE", - "extended_unsigned_section_aes_key": "CB15F4F517DBD310BCD5FEA2DFEBBF26", - "extended_unsigned_section_mic_hmac_key": "865316C4BD1F483DF2FB1F819AFD6798B26344E9CB7D5F33C0FE5AD5C8DBC1E0", - "key_seed": "4129B6D0A4B84BA1F7241CCC11F9C75EDCB74E50DAEDA9B94E7E5EAFD418921F", - "legacy_ldt_key": "A3322720422B4E51C75B1C66F3BD3DF06DE13496B38FBA0BEBC4CE11B12238F3C779A2136C2B616F5E680A9A708E5E2CCC3F8AE9F0047AEA0B1AEA088C823EC2", - "legacy_metadata_key_hmac_key": "43C5B9A88F6818DCEA6F93D49466F31BFFD5A4EBEC3C2ECF5A872BE86F5B99F6", - "legacy_metadata_nonce": "A3CAF797ABC475FB19F5B602" + "v0_adv_salt_hkdf": { + "adv_salt": "B490", + "expanded_salt": "F5A6423790B75B0A73E26647F83E003F" + }, + "v0_identity_token_hkdf": { + "expanded_key": "1143418D5D928DC46A5764F53E7065FF", + "v0_identity_token": "5A6EB28E3F9F076AAF47F1AD6F52" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "AF5C", - "expanded_salt": "C7F68B27D565702CF382B680B8E7055F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "5B71", + "short_salt_nonce": "446675E4C5503E587A7ECD0E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "1CC170AD6BC9799CB87FECFEB7FB593B", - "legacy_metadata_key": "4D860E0531136A82B22D80EED522" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "CB1D2C8F670DE3E029FA9F91D0FC1494", + "derived_salt_nonce": "F82D6616C9669EC7708B6C085A45E8F8", + "derived_salt_third_de": "8ACC53A66823593B9F10479985B6D9B0", + "section_extended_salt": "839CE97E9C32C0C81368ED8F8057FC02" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "EB90E68FE9C38FF5A956B2DA2D44D399", - "derived_salt_first_section_no_de": "014EA160B58368629BA76FF16A844341", - "derived_salt_first_section_third_de": "9ABC5ED7EF8973C8FF865B6174CF18D8", - "section_salt": "04CDB186B08FB26AF67486FA439CA9AA" + "key_seed_hkdf": { + "key_seed": "F8D48367C0C15E86ABD63D96C632504F7ED68866436F6CF694D7926BFDB460E6", + "v0_identity_token_hmac_key": "02840A91CA2DB99828CA95C4A6102EB14D28554B01ACF4EDB70A8CFAFD0ABF1D", + "v0_ldt_key": "DDFB10BC34B1A507695E663B936379D7F8F5E3A58960B0D54D286752784414F4AC7E3D86F480BBE83F3D43F99E45E2787A57D234D26C43881BA12BDA5B8A84F7", + "v0_metadata_nonce": "31DF1F26F5C80D57D312E8FF", + "v1_metadata_nonce": "EF1FE145CA3643D332ED685A", + "v1_mic_extended_salt_aes_key": "681A2CB23B847D46E355E0625988C8DF", + "v1_mic_extended_salt_identity_token_hmac_key": "CD02ED35449659F983FB2070D2D353311FD04A1529DF128F097FB28447898FF9", + "v1_mic_extended_salt_mic_hmac_key": "26B0F39B6880F40FBB6D006D3FDF20FA75D61FE70A21AA279295303AEEAAE57C", + "v1_mic_short_salt_aes_key": "A0082298B9261FA98FF77171F7FC6D35", + "v1_mic_short_salt_identity_token_hmac_key": "DA9EEED06B73B51582DBB749CAE10B30A072B4CFFA13B3055BBB0DCFAE423D7C", + "v1_mic_short_salt_mic_hmac_key": "28D6FDBDB521166652ABA223A3FB626DAFB5E5600D72B7EEBCE1A95E1E62CBAA", + "v1_signature_identity_token_hmac_key": "6A82842B2EA2C3C17C26B2867FDCFDC4733F67D4486CB92E1436B282A2E63AED", + "v1_signature_section_aes_key": "066127DEAD9D2611AFCC7B6216F8F180" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "3820", + "expanded_salt": "ADCD23D7DD53599418BFA63474D69B5B" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "69EFD440262ABCAD6340712C", - "extended_signed_metadata_key_hmac_key": "ABE74AB6340DB962F20CC9D40EAD220DB2E644547F110AAE1AFA59E98ACA5073", - "extended_signed_section_aes_key": "C30E2EE7462A487197359E2B1E6B592F", - "extended_unsigned_metadata_key_hmac_key": "46BC94A1996B114BB3EDFF2EE8ECA2A897EEC62704CB2EDDFFD5B97330E770D4", - "extended_unsigned_section_aes_key": "F3ADC71F3D1948E5609C740FE8DC5DFD", - "extended_unsigned_section_mic_hmac_key": "45F4745792A7129CD8864CDFB715B7047356DF99F7A3ECDFA4F1191C2EEF39DA", - "key_seed": "8D228D34A11D8C6E89BEAD97C32CF1CDEB83128EDE806AB12AC1C315104A12C4", - "legacy_ldt_key": "58B087E71D5AFBE1B2C9D40770425BF2F950EC54A80BD266A8C3DC184F4FCE7F6799BC221FA5FE4025EA898632E2F3D3C8A983E9468B99AC033002779395CEB0", - "legacy_metadata_key_hmac_key": "79C5E3C3D6BBCB4FD9BE972683D273484578E592AB7808B1A2DBCB6A0AF0EB20", - "legacy_metadata_nonce": "22C6BF85F720FB130D698F43" + "v0_identity_token_hkdf": { + "expanded_key": "D886612612F2CF8F0C8D2FEC71A2FF37", + "v0_identity_token": "63DA95A649039DDE7129B93519E8" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "AA36", - "expanded_salt": "1DCEFB9DA72BA3A4AEF988EA5C803E39" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9A3F", + "short_salt_nonce": "7D16B77869830EE92A4EBFC5" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "60989D8A1EB13AE51250E2698F544BD0", - "legacy_metadata_key": "E9B69DC6D89A0FB49D43B34F5311" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "659B8A721546530DA9795AF4F85F3172", + "derived_salt_nonce": "C86E1DF850ABF4050CFF5069AF064842", + "derived_salt_third_de": "5409D2E3012D6087942D9C6A9AD01055", + "section_extended_salt": "618434E133FE816E6B612F6CA5057231" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "64555F0FD7574CDB19BA389CDFBC543B", - "derived_salt_first_section_no_de": "3E0E5C26DD09AA19522AE9FF60E299B5", - "derived_salt_first_section_third_de": "2177B3044D79C03B816CD8E8433C5B3B", - "section_salt": "BFE9AF6A7740CD26E60E7C5A8AB281C0" + "key_seed_hkdf": { + "key_seed": "1908DD830FC3A7EE0E0FE2B559BC1DF6B5C80F9576452FCA38995CED1EF3D9DF", + "v0_identity_token_hmac_key": "3CEB70A041FC1EA8969A7FE0ED5C0B26919747CE6E32793B7928D14934CF1921", + "v0_ldt_key": "82B1C998FD20CB2053674D3BE231763B9B4445B16D39E23C054985F315717C2D842817F74EE526D4F3CB50FA7CCEB30C3DA0B5DF9D39B19A8E51917E56905CBF", + "v0_metadata_nonce": "DE3382B2F3E85062C9C945E0", + "v1_metadata_nonce": "73FC91F971F797CF852BD47C", + "v1_mic_extended_salt_aes_key": "7479E783DF7D3F949C85D44150538152", + "v1_mic_extended_salt_identity_token_hmac_key": "4E8FB9F60DC947E7E6ECCD42D235842453C070432703EC381BC44F65F17A944B", + "v1_mic_extended_salt_mic_hmac_key": "081D31934C99EB52072EC7ED6D5DB9B238E8E9E6A1E66F612C3A53CE664895E5", + "v1_mic_short_salt_aes_key": "87B5CFFAF5E8BF3F76F901E8A8167EE1", + "v1_mic_short_salt_identity_token_hmac_key": "02926351AC11AB30159026DE19F8860825CDDEA95AE3B4054564EE4F42AAB436", + "v1_mic_short_salt_mic_hmac_key": "E7B62E504AF1F2EF99A86EB37FB14AB5642FCAA0EAD4BB0636D65A41B455A876", + "v1_signature_identity_token_hmac_key": "8E1E4E0D0082011E31322CF3CCF5CB6DD94F041C529255A3E96215C2EA887B86", + "v1_signature_section_aes_key": "113BDF8FDEB7FDDC45EB8D0CBFAA35DD" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "34D8", + "expanded_salt": "E1726AEE6C32008D70E77FA3CA10A3D5" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "8F2CC361A133B662D60E70B4", - "extended_signed_metadata_key_hmac_key": "14F28363041B1AC420116ADBE5E862E36C4F209C68D784AAF659003123931F20", - "extended_signed_section_aes_key": "F68813A0A51D3A7D6460C05109EF1730", - "extended_unsigned_metadata_key_hmac_key": "6AC0B8555E39508D3F72BA8984E530E59A42777BEB16A2A6CFC760345AB6AB13", - "extended_unsigned_section_aes_key": "F3DF15F42B2DCD3617C60847F88EC279", - "extended_unsigned_section_mic_hmac_key": "149F3635D7BB841DE87493388AF27E75F0D5C374DF9108C5865EB3F1B631AD1A", - "key_seed": "0D4D259D5D0E5D7C9B2A569A1C17D389E618B782D1BCE04F8484035492CE11C4", - "legacy_ldt_key": "E1628A30487D83BB90ED7B5643AE314CD9FD98C9679F37C25D922DFAA0FFA66999FDBEFC099EAC5250C6CBCBA2314085DBDEBC4341A2074226D3E92773B1946A", - "legacy_metadata_key_hmac_key": "9549B17906EDCEC2E747744703EF977F5236528197E55617F93755C860CBD0B5", - "legacy_metadata_nonce": "BAA28085EE97A8DF527A5594" + "v0_identity_token_hkdf": { + "expanded_key": "9FA9C4CEEB36C5D01308572338AA4DBC", + "v0_identity_token": "4468295C7F2D6B52CCB9519B5C18" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "57EB", - "expanded_salt": "D275F5AB0B47DB46096D6A2ECDF58D52" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "51A7", + "short_salt_nonce": "B61ACE6DA49F07333D36D94E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "F3B453CA100ED3E10C91E12A7481F4CB", - "legacy_metadata_key": "859FCE97618BF2DB58D184DC53DE" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "B2DB55B0EE6A19591335FD4A004AED74", + "derived_salt_nonce": "A18DB7BB4DEB0BAC4C300C1DFF08300B", + "derived_salt_third_de": "65FE8535564AE2CFB9D3D19CD5F1DF30", + "section_extended_salt": "FC87C8E278F6CF79DFA952B70D3804CD" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "74F425482431EB42FF996BAC1A227F0F", - "derived_salt_first_section_no_de": "CAC0DBDE04AB7B70FBF8A40E18814286", - "derived_salt_first_section_third_de": "B751EC2415541106D79351A34AA5D2DC", - "section_salt": "4B0BF5D2EE37C72845CD0776F7AAA512" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "183FB3B68B7A48FFF0C161AC", - "extended_signed_metadata_key_hmac_key": "50027ADA2FF20DD6132B1729D7CDDF3D6619EC2F0B676D68946B199C65EDF004", - "extended_signed_section_aes_key": "2C4916F70427AB1247D581CDEF656639", - "extended_unsigned_metadata_key_hmac_key": "211294989AB217BBC4794503C433B7B886612E2D9A8B824B0EDD590F2DEC8B7B", - "extended_unsigned_section_aes_key": "FEB3354D18E5ADA3E7684F96EDB719DB", - "extended_unsigned_section_mic_hmac_key": "144845A3ED634D768F0F4E4BCEED5E9F23D77A033D67FDBE6F1BA225FA0A71A1", - "key_seed": "2B4907289260929651D6339AE8157C6F509BF34AA7E2672B5C671837C62A0363", - "legacy_ldt_key": "2A1BDC158660033902E9EC6F47BCF81C99EF5AE759CB03352320324BEACAC4D62F816CA1A190BCC28A276838F565FA5F41E2A7BA8574FA77D61F2A83DCDF665B", - "legacy_metadata_key_hmac_key": "1266E50907BFA5ED5990F295F10B1562D4780775A3CC95F2F5D7DD9912644961", - "legacy_metadata_nonce": "27B1A368FC746D389CAB7604" + "key_seed": "D9C3778AA9B5E3B681176C33F23D930EECF65E3B03F57383173FF1C961C43632", + "v0_identity_token_hmac_key": "6D9F5B36A298BC2BB69628BE19C027B5B82EA49BBF39938CA796BFFBA80BDD6D", + "v0_ldt_key": "515D7D78685E974EFEC733637B866911EC2DA076275B073B53B8474C52B4EF97A0BB4BE23CEDD04EDD320BE099E42C17690B9FE34543D0BC56F10E706185C735", + "v0_metadata_nonce": "294F93F189066B9962BE5F28", + "v1_metadata_nonce": "7C2775AFCE63CDF40320A5D7", + "v1_mic_extended_salt_aes_key": "3083165096C985AFD9634D7C8C27B241", + "v1_mic_extended_salt_identity_token_hmac_key": "072CD33806FF7BC19C06232406E694417FC54B2A5CFB07F7F6B8E9F41B05CA5E", + "v1_mic_extended_salt_mic_hmac_key": "6787832FCFCE8782338608C8F35419AC877A130B4AA7866A3C7CB22ABD67179D", + "v1_mic_short_salt_aes_key": "A3798AC54A640D75DE9460BFF32D5A5E", + "v1_mic_short_salt_identity_token_hmac_key": "43DADD838D1B76E2EAE5A94FB1B839173FBD84CA47BC35CC2AA508D9D3516823", + "v1_mic_short_salt_mic_hmac_key": "F92977DD9EBAA721832F6E5D0CED0E29F940847AB0FB87494F323EC770EAF6F3", + "v1_signature_identity_token_hmac_key": "28A9E655ECBB19E0C72E389AF86D18CC1DD99B837CA39F80EFBEF46562ED30DC", + "v1_signature_section_aes_key": "5882688026AFC05D0A53C691D3C205AF" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2CF1", - "expanded_salt": "2D9360CAD492BF9B3F8BA5659FBFD479" + "v0_adv_salt_hkdf": { + "adv_salt": "BB77", + "expanded_salt": "5EEC79CBDE9B59FB7CFA09BBD4C21F6A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "B04A6E310A7D824C2ECBAC27C078CF20", - "legacy_metadata_key": "2E262ABE8F4651CE3875F82BBF18" + "v0_identity_token_hkdf": { + "expanded_key": "9C80752325978A05003338C9AA98CA51", + "v0_identity_token": "CDCED4F23EC9AEAF9254F5851E9F" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B8FC", + "short_salt_nonce": "C4625EB21060C7AC6EA7734A" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "2040080121468E2437D7C4AF1AB57CBF", + "derived_salt_nonce": "ED3C0CD523D93752269A7AE558DA70D1", + "derived_salt_third_de": "7EF0A5B6DB0312484B90580CC5CCDBF6", + "section_extended_salt": "DD49906314C2165F3AA4887C7C2CBDE9" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "A36E49ABD02685DAC38CE1D19D0B8B9E", - "derived_salt_first_section_no_de": "D531C60F8CA7C63115E838F71519894F", - "derived_salt_first_section_third_de": "722AD6D5D32103BE533568A2C3903320", - "section_salt": "581234FE7E1189244C5C61BAFDA5DDB4" + "key_seed_hkdf": { + "key_seed": "BDB42D1F4E1C41E35B00D54D726D90A18D9EDF326C5A95792C6A8BCB47F3D8DC", + "v0_identity_token_hmac_key": "4DF296ADF1A25ACA84D578855464E8A91903FB5FB2925D4F7AA4EEB667C3F514", + "v0_ldt_key": "A34CB3B18ED974E8C932C3F776D8D640D044E8EB23395507EF2E27143DE60549E44A2CCFB545900C84020984F1CA4ACE171E2150CF3E37CEA49128423E96EB6D", + "v0_metadata_nonce": "4007F919792DE5E3D9E35D6E", + "v1_metadata_nonce": "E95F4B6766CCD3571F404E51", + "v1_mic_extended_salt_aes_key": "5355412E0561A0BC09520C23F88E33AB", + "v1_mic_extended_salt_identity_token_hmac_key": "8324D08430C2B565D5E4E3FD00068564C096FCEFEAF026A714033726242A6EB5", + "v1_mic_extended_salt_mic_hmac_key": "80025D8E9667BD088B5F9D297EEB6AE6323204DED5D6A5823E28896F58D703A4", + "v1_mic_short_salt_aes_key": "3FB967135677C8DDDA512EE813CB7143", + "v1_mic_short_salt_identity_token_hmac_key": "E9A7AF77D3A9368BF553BCA5721EA1F9981877501C5D999B437FCCF1E92086EA", + "v1_mic_short_salt_mic_hmac_key": "7A93B87E26BF91DFE19D314D0D1E50B85CCE0BCB90AA127706A328F927092721", + "v1_signature_identity_token_hmac_key": "39062B01DFC854FE594F8D6542FA644CD5C969E6F227511F4865D974CC6DEC2A", + "v1_signature_section_aes_key": "4B1167F08673796EC85DAFE62137B809" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "45E5E1444674572E775B8224", - "extended_signed_metadata_key_hmac_key": "E0B347400DE60F9FA04DA4ADBAF3B6BD04C644F6793CE46F85CB71479ECF3EF9", - "extended_signed_section_aes_key": "B6DDDDAF922C963512160E75225D09F4", - "extended_unsigned_metadata_key_hmac_key": "AF0BE49B0E816D8F7712328C5F4E6ECC82DDC48892B3BDE3F1C4C01E5FA03136", - "extended_unsigned_section_aes_key": "848215F6E61B20D5928039AD45AD2132", - "extended_unsigned_section_mic_hmac_key": "8B905A2A15AD9CF4FB406828D832C9A035D4230C0F539D7647C55022232A9FE8", - "key_seed": "32DD54629DB08642CDD3D8FADA206AAC7283C4CA3E2A8C555AD8DD6598720562", - "legacy_ldt_key": "4274705A9EB207FFA0F1D42694C47173DAB548F1255772A438CB64BC9A03E80C50DC01E2F201BE9A1FF32E40C9008B4EAF1242A11CA3C0B4D398419369228C8C", - "legacy_metadata_key_hmac_key": "EDE5263B245DA34B73AD72B20E1D07CDC64A814F65676AD59F056B31D3525B34", - "legacy_metadata_nonce": "AE685D297E2D64B79DC9C2B7" + "v0_adv_salt_hkdf": { + "adv_salt": "F252", + "expanded_salt": "EA39B41EE8AE4A6EA4EEA497AEA49449" + }, + "v0_identity_token_hkdf": { + "expanded_key": "53559C87298B9802AA805237D5652703", + "v0_identity_token": "CEFBB6A76E7EF5CDA4D26ED815C7" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "8CA2", - "expanded_salt": "49637910997ECD98BC7F3190BAB36A4C" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9E68", + "short_salt_nonce": "0956F02109DC68655CB62A5E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "BF435149C0B6A7FA723E18855A5D02B2", - "legacy_metadata_key": "96FD3B89B68B0B14A3781DDF9538" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "93BD8DE56900BCEDD84B9A1978AA94EE", + "derived_salt_nonce": "66881A93AE754517DC4D61AD12F5E742", + "derived_salt_third_de": "BBFD5FCD7F36BA90D88A9A092F8ECA29", + "section_extended_salt": "4D1E91C6292D4A910828E53CA3F09EE3" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "DCBBEE3140866817D5B3E64BF6AFD60F", - "derived_salt_first_section_no_de": "C7DBA60E81BB4A0F806B82F9DD4DE170", - "derived_salt_first_section_third_de": "00C8B3CA67C7C566A850C3E17B7E3A29", - "section_salt": "80FC0A629CE7F0CD7B603F171F162D24" + "key_seed_hkdf": { + "key_seed": "3B47B274E1880F0D735A3A461608C79800450B43A7CF5144AC1106AEBAC9826A", + "v0_identity_token_hmac_key": "A45E22C2CEA0F70D106AB51893CA33D0DF68701EAD7AAACD3D5A9942FC5F0DFB", + "v0_ldt_key": "FEA32307FE627BC3C5D33D748ED4A00AD9002CA2B10EB72F85BDF82F0275B9583B73FC02ABEC26E891AFB24C340EFE8EA4C27E7C4D28FE44ADA6BF10E899F561", + "v0_metadata_nonce": "6E5B371C46E3D16E4D5A66BF", + "v1_metadata_nonce": "7F261DF35ACEEDAA4B576F1A", + "v1_mic_extended_salt_aes_key": "BC74140188830CF38B8C241095BEB16C", + "v1_mic_extended_salt_identity_token_hmac_key": "385EE3B943000B9ADE0DEB825876F9F56EEECB6A72A0FFE15FA2FA958B1AD6F9", + "v1_mic_extended_salt_mic_hmac_key": "4B68A5067578BC2F7618F8B47F1FB64F3D304FFAE521225A895555BA5D8D9340", + "v1_mic_short_salt_aes_key": "DE089E6F3B702F1BA314CACA9E7F2788", + "v1_mic_short_salt_identity_token_hmac_key": "B2B5C5D2DA5C6FF0E1AF067248893051884AC530852A1EDD47CB494FAFFE06A1", + "v1_mic_short_salt_mic_hmac_key": "0263DBCBE0F69B101A639B2CF16346841E5ED159FAC9DCE93F92019A207D5819", + "v1_signature_identity_token_hmac_key": "E9F139462C5CF1CCB22E216ADB16B13C04206D39DABAFAAD83C342010BDCDD78", + "v1_signature_section_aes_key": "2DDFA0C2E734D9A8698821320CF1FE8D" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "CA66CE6D69EA86A41AB0F413", - "extended_signed_metadata_key_hmac_key": "6EA8DF938647F825C60C6251F0CC1CD82FC642A0E254EF2620A746F46C9E1258", - "extended_signed_section_aes_key": "0F0B94A88E78E605C74B5B91AE62BFFD", - "extended_unsigned_metadata_key_hmac_key": "6C5D462BCD86343B68C4435D5B1EF6CF9AFB3C38F226AA84B7ADE93CDB23E83A", - "extended_unsigned_section_aes_key": "E2C02DADB79D7CBFEA71F94C4A65575D", - "extended_unsigned_section_mic_hmac_key": "38350921EF19BA63EA5D6A5511230EA652628101961EA4504A597C5FE4510591", - "key_seed": "3836F8FDE174BAA5BFCE8F199CD45AF774C245312F90939B6D6FF51892F5C549", - "legacy_ldt_key": "EC34EF3B3714001DD85534A5D3600A70645B612F7E8937362E43C683149F6F5621C3E2F700EC3E9E40AE468116316DB52F85746E6B9856FECFD94BA6BA852AF9", - "legacy_metadata_key_hmac_key": "7B2DE270684F7A3872B5752AACE00BDA88CA3D832833432EF1FCEA8D04523E59", - "legacy_metadata_nonce": "5A9EC7E213B30C88FB1F32BC" + "v0_adv_salt_hkdf": { + "adv_salt": "3D53", + "expanded_salt": "5D92CE2F393EB11F68AE3399C3C6AA13" + }, + "v0_identity_token_hkdf": { + "expanded_key": "6541E71B9A62F202963E4C541DBE6DE1", + "v0_identity_token": "1E65BA9B2D61AF735D60781F99F2" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "EE17", - "expanded_salt": "D206579E8B5DA9132DBF4D1582A846E5" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3F94", + "short_salt_nonce": "85714E38445BE9A4C2D012CF" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "BECFD5FC4083874524BD1E5A11A15CEF", - "legacy_metadata_key": "FD47DB9B922B170C9332494805DB" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "A7C1B418774DF806054C029FA82533F7", + "derived_salt_nonce": "4919EFBFB04402814AB0C6A805820947", + "derived_salt_third_de": "C55544C75B968C2EAAD88699050D4362", + "section_extended_salt": "2BE31AA1F7D93AB925E36C8E96D2FCC3" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "BE32AD26A190F96FC445AABBCB1CE959", - "derived_salt_first_section_no_de": "8F061686BF5B1411A332C523C4E0A209", - "derived_salt_first_section_third_de": "232C9AB5D992F3411339C60540915063", - "section_salt": "8C2DCAFB7C90877729124D34A7D5B6E5" + "key_seed_hkdf": { + "key_seed": "F13F7BA40A43DFB17FB31FA4EE756C48B9FD924F19EF3A86CA524B838A4ABF88", + "v0_identity_token_hmac_key": "280DA0042A5A21602B1D11DCAD91AC32691973312481855D05C221E4B3CD4B20", + "v0_ldt_key": "AF35739784D80E88F6AA2948111E905B95DE18AACEF41358A1A1C99D9C95BC67D5A62523FAA0E929AA7F83479F1A5D30FBB8E349A04A085F5AB28562B3BBC681", + "v0_metadata_nonce": "0A9504BB121E12DE3E8BFEFA", + "v1_metadata_nonce": "C63F427096971F1752F6221F", + "v1_mic_extended_salt_aes_key": "01EC1263EDE7F6EA26031C28ED8E6EC3", + "v1_mic_extended_salt_identity_token_hmac_key": "58C76F2F174E8B026E32BA4A09896898E39A21A4B4C6AFB5CBFFDD3F17217686", + "v1_mic_extended_salt_mic_hmac_key": "59DD79D819E0C6E50E4189CC394B7FDE1D1AF17E29C9EEC63727F64430A1DE9A", + "v1_mic_short_salt_aes_key": "AD577ED2A071A7EA5BE2DBE3D9440CAE", + "v1_mic_short_salt_identity_token_hmac_key": "E6A27A0F3EA35DA104296F11B2D3D7104DCDD066FDD3930D2A8B4370C0497F27", + "v1_mic_short_salt_mic_hmac_key": "F5D81846C62C536E3D6B19F3A33F6DAB14C708EA183E6D598DABD4D567DB2C21", + "v1_signature_identity_token_hmac_key": "03BD502076C9F2CA53775BB46DB7D0120297DCE95C9D455EBF0D5C588A31FCA7", + "v1_signature_section_aes_key": "8559B5ADD92D397DE221F606DA353EB6" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "5B56", + "expanded_salt": "0F102F204F31D295E3B9FF1956F387E2" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "23CDFE5E54488821F6ED0A27", - "extended_signed_metadata_key_hmac_key": "2B262B746F258E0AE1CECEDC1C761535AB94C83536FB700A8C005F7DD418C388", - "extended_signed_section_aes_key": "DBAABCE45273B37FD68B63B6957E5785", - "extended_unsigned_metadata_key_hmac_key": "E177B64123EFE628A6268D943BB7824EFF52212CACF2E3F59C07E165E4F16637", - "extended_unsigned_section_aes_key": "B085C6252DC18DCD41D7F83A28071565", - "extended_unsigned_section_mic_hmac_key": "32CD283375EF7007BA71BA8540A8AA91A05AFD714FE80809A9F92F0754F3CC72", - "key_seed": "2E489B259C0566C778FA0ED37E2E7FA41DF3A664CAF4EF875A4427EDB479BB23", - "legacy_ldt_key": "68682B202007B1B9DDA6871451170B1B093C2A051C7C5416E71313ADC01B5F61C9E849A9C2C1CECC480F8658C6A649F195EAC21EC41749E4E9034894B1A13462", - "legacy_metadata_key_hmac_key": "9B6569331C5F5BC18C8444EDE38A946F59FF525D71C9DD3A0C0AF93BD799EF34", - "legacy_metadata_nonce": "A6A810AA0DCBD8FB7C957713" + "v0_identity_token_hkdf": { + "expanded_key": "D6CDB0E747062077D2AAAD00D039B656", + "v0_identity_token": "EE348B9FE43A8F854A90FD246EA3" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "76E3", - "expanded_salt": "DB8C04B9A21DCCEC75C4D2C7806F57AE" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "F5EC", + "short_salt_nonce": "A1FC444CC695E3DA1BB17AF0" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "0243B20CDF5D6EC2B5F40DE90BD517C6", - "legacy_metadata_key": "10D3F1C4B9422B343140B77FC230" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "04AB6D4EDA19FC328F24C74CAC5C5DD8", + "derived_salt_nonce": "9331647748783F90E401965AC5B87106", + "derived_salt_third_de": "42CC023EEE82C7E84914B2E8190BF169", + "section_extended_salt": "B877CD0EC34F48EF8AA9E00297D82C64" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "CC2F52EBC86DB28E36451CDAF13079E4", - "derived_salt_first_section_no_de": "DF2CF0AF9608449FBD2545BEBE111B51", - "derived_salt_first_section_third_de": "0B60FF977CD4A5D900642F660C496EC8", - "section_salt": "3D36E649B2617F943C57E5845043BD7B" + "key_seed_hkdf": { + "key_seed": "B6400810BB927EFD733610B7E06F0D73DF1AE94274346CE0AB15CF95EC2A074D", + "v0_identity_token_hmac_key": "663D9BFAC9D198A1874C1AF13E986B22D94CEA5DB82FB8CC26DB95BCAA78C363", + "v0_ldt_key": "52C970B142592DF27DE130EF7C1D51F6BF2D191E046FF815A1C340AD8A10CC7D1C7A917F1989706C7E1AF8749BF7C2E97388BAFFF56EFB7DCDCEDDC3DFE1B42F", + "v0_metadata_nonce": "1340C3F2C220EAB0864590BC", + "v1_metadata_nonce": "739B0EB3925CD78302454F25", + "v1_mic_extended_salt_aes_key": "983C9CBDDD7F5D76D9D501819218974B", + "v1_mic_extended_salt_identity_token_hmac_key": "A07289F3FCFB896BDE3289DD42B12D30C2440FA3A556DD58F7C87C305CFFA533", + "v1_mic_extended_salt_mic_hmac_key": "41DE5A06B3108EFDAFD5B8072E5438D0D411EC26C46C2EF62742D31E7601442D", + "v1_mic_short_salt_aes_key": "2A3B1E230B36FCC470FD65299A7EDA9E", + "v1_mic_short_salt_identity_token_hmac_key": "CCA9DE895F08980C2709A0FD4CF1B835E915BEB5E5BF192D5D30AC918E100C75", + "v1_mic_short_salt_mic_hmac_key": "80139B754D19E3896A1E1A5025DD04FC8E699B879484D8294A77EDF648E5643B", + "v1_signature_identity_token_hmac_key": "C6D68149007593DD02EE8790467405844C978F9352DDF2545C813022497DA7D1", + "v1_signature_section_aes_key": "738E9ABCFB9D5461E3F8E249C5BED287" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "77F7", + "expanded_salt": "999BAACA7F0F4EC499FB4984FAD96C5A" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "92124C3375F66E88EFE35C53", - "extended_signed_metadata_key_hmac_key": "A0D58D77AF063A719AF9FF4EE9073C16B9BE7624AAB46951032E2DCA7E58F9A9", - "extended_signed_section_aes_key": "2B11051C494B15EFF095B1CE27731780", - "extended_unsigned_metadata_key_hmac_key": "0DAC827E8E114BE7A5377C68A902C3F9F9ADAA3799DCAB115B4402D6986B6693", - "extended_unsigned_section_aes_key": "9EBE28389C5D4037FE9CE66E5815318A", - "extended_unsigned_section_mic_hmac_key": "575A04282694E59058B0B62D8EE68F9F97063EB4CAADBBBBDD49CCD58C00AF3A", - "key_seed": "0A188883B6CA017E98A98E6F25D090AD8B59432D5978D9B54F41A7E4F60BD880", - "legacy_ldt_key": "C393CA2F2A769B0C37F6F394C806FAB5E6D73AE829B7AD0AA58351D65A8436D09F67C076069BE57AE561CFEC65DF13F31A2D78C583835335B9E79D42667884E6", - "legacy_metadata_key_hmac_key": "CC4DDD317D155D714F0BCDCF55F7C7596B9593B5A331561D1E075D63605F1311", - "legacy_metadata_nonce": "9D15BA91B10DA670512B7F69" + "v0_identity_token_hkdf": { + "expanded_key": "0800A0075D6EBBB3D36CC9E504DD12C2", + "v0_identity_token": "4F53F51F11499E9B94A03C1A12F6" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "0786", - "expanded_salt": "90BF5725A647F3877EACDFE93F00743A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "FCB0", + "short_salt_nonce": "7B035FDE619F1DC6DDC82276" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "44412FD614B0F95EB598CBD223F560A3", - "legacy_metadata_key": "3A127741C99A09FD4F7416C678B9" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "CF464723DEB71D8CB55827A0DF0D10F2", + "derived_salt_nonce": "5DB21C018408C6854005F5854F4FC0DD", + "derived_salt_third_de": "4F8C68AF4DFC9F31706823CEC2CFC31F", + "section_extended_salt": "F6F7A20A1113FA0CBADEE03D8737309C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "BF6F7B9731537CD65957FE062847164E", - "derived_salt_first_section_no_de": "7A4C1F1972B35CB2F1D8ED706210BF86", - "derived_salt_first_section_third_de": "86D64154463B1BA93C139DDB0476F29E", - "section_salt": "006BC21D03AFA7BD1316E76B52AF72AA" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "460BECD309A3EE6B35175031", - "extended_signed_metadata_key_hmac_key": "63CB2E1C16F5B94BFD5DCF725B322E2EC4CFED49BECD757FA4A5066524875C15", - "extended_signed_section_aes_key": "7D3E000289F97FEAC66DBA48492A985E", - "extended_unsigned_metadata_key_hmac_key": "3C9232DEF5692ECB5F753CF1CE5AE15F1E251881D947B0EF726D86720C1E03A4", - "extended_unsigned_section_aes_key": "A2FCCB33B71B1A8D807DC1D9241584D2", - "extended_unsigned_section_mic_hmac_key": "52C00EB623D242318A865DAD8FB76A775F6D5D80F5CF030CED9777F6B704E9B8", - "key_seed": "B48D65795DEEF4190966FEA215BB96F6052507BF909CB2DD5345E9FDEDF321CC", - "legacy_ldt_key": "22F49B6998414150E646326B75F7AC83CF5DF705B33C582310A963116845F5E00B2937634AA8338AF18E9B45EC6C892708924A0868051A44ED4561D9D091F47F", - "legacy_metadata_key_hmac_key": "8A28B3F414B387807148BB37C2C74977C2755E41863DAAC7B15E3B7C006A5E6A", - "legacy_metadata_nonce": "1CD3B2E498B4D30985B1E11A" + "key_seed": "F100C4BBC5B202507F057930DF27C5920882EA60BC5A770D33793133CF247746", + "v0_identity_token_hmac_key": "473297E18614DEF67B65E9C7857176A793754ACAA1530102AA81A082D58F7D02", + "v0_ldt_key": "1BB3499572A9AAD2C719A8961D95A1040DEE023D5933CBF52938A2A4880C5339C7EBB4F54DBD9697FF470A5F50171C223707B568E48CC4287DD309A855912E11", + "v0_metadata_nonce": "FC4F23D0384FCF4830D1E499", + "v1_metadata_nonce": "0AAD6D64DE1D90C577F60248", + "v1_mic_extended_salt_aes_key": "17A86CACFCE67DCCCF875B0AEA29A5D8", + "v1_mic_extended_salt_identity_token_hmac_key": "93DCD02530F3C29DB62667D5FF2FF8C5EC81341A7F642C0BAAF3D16B82E051CF", + "v1_mic_extended_salt_mic_hmac_key": "020BF714AFCC97E16CFED3A9CEE5490B0C72B649DADCB7F0D31E1B9EFEBC048D", + "v1_mic_short_salt_aes_key": "C82D0BB3858BCF0818755B90B87467AD", + "v1_mic_short_salt_identity_token_hmac_key": "99700748DF89599EC8CD6A0464EC084651BD335DD8D8D82956E405D0994F2325", + "v1_mic_short_salt_mic_hmac_key": "FC3B070CECBABBF42ADE9193735C6D66322A12A1C3703C59194B823E5BC460E7", + "v1_signature_identity_token_hmac_key": "700DC0F4F8D9AC2B6A190EC7D041F0E6143C99CBB4C39C83419C5CB2382504CB", + "v1_signature_section_aes_key": "1D268051F9FCA0FD696862C2DD230F97" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2619", - "expanded_salt": "11CD75FA9ED0CC386D81040E5E28BD5A" + "v0_adv_salt_hkdf": { + "adv_salt": "0739", + "expanded_salt": "57E814971788FDBAEFD41AE890DA236E" + }, + "v0_identity_token_hkdf": { + "expanded_key": "07F23FA7ECDCFFFFC98A7B46B0382C69", + "v0_identity_token": "92DEBCB60F3BB1E5D5D3BE1FBED2" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9A12", + "short_salt_nonce": "BADA73EFD61495DD37336600" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "6F0D67269728308DBCBB1DF1D485512C", - "legacy_metadata_key": "F3FA997825C9B8CE27114093994F" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "22820FA9A35165D2ABF6C7C256681574", + "derived_salt_nonce": "67DC58AD06F080D8A671163E36A4F0F1", + "derived_salt_third_de": "B5DE19F288B57D8338FCB5134D7FE17D", + "section_extended_salt": "14C2765287EFFFE0153EF93894134505" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C4394DDD7E50753EA4F6A380BEAA6D75", - "derived_salt_first_section_no_de": "9FBAB23311FF8DC91ED5581625BE5C31", - "derived_salt_first_section_third_de": "7EA2A3C3E08970ED0ADDDA2EE28989E3", - "section_salt": "F7802897A51C9CC8CB4F39237AA5AF75" + "key_seed_hkdf": { + "key_seed": "D0E768CF45FC018A6C3B9B78634E0D8ECCA218220BAB479F14327CBE273AACD8", + "v0_identity_token_hmac_key": "7706A0543B4EB81B1555D989161EF86F617DFE7A93F87EC62D239709DCE3F2BD", + "v0_ldt_key": "8B3422872ED8BA90E9378F20B5C066846358D7238979499D2E32DC657C359C0511BDA2624B8F7F1C6BD93C08A7DA716035D720DEBE02AC0A3F9E0CDFC8B979FD", + "v0_metadata_nonce": "69E6E6255195E8ABF8C191DA", + "v1_metadata_nonce": "2A6B45C6C1A4B8B0AFECD887", + "v1_mic_extended_salt_aes_key": "DFD9F7A823818E211715841828D9EDC2", + "v1_mic_extended_salt_identity_token_hmac_key": "AD329A4E049CA3B4F621DAF087A88ECC5B318AC36D92EB3604ED1FD7AC997DD2", + "v1_mic_extended_salt_mic_hmac_key": "C4C4E9B64AFC367473E38D66B110403284C3C03AE00F1BBADC230C93D5D97BB7", + "v1_mic_short_salt_aes_key": "7365641B35E3A6A5863106192EE1E1D1", + "v1_mic_short_salt_identity_token_hmac_key": "F4DB33EC5EB13864F6B46DCDAFA9399E0B5F17C111D275C9BD906FC46D45D38B", + "v1_mic_short_salt_mic_hmac_key": "107A3B99DFA9D082BA9C5A52D066F0517EB0448B4CD3CE2671D6E191E2E2ED08", + "v1_signature_identity_token_hmac_key": "67E13E77F909D2E4A54AF23DF1319098A1CF63EC9D69ADBE1C1993CDA198AD7A", + "v1_signature_section_aes_key": "0CCE0847357476165E32DAB0D93660A5" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "D429", + "expanded_salt": "B293DDC05C6AE00B98174666AC83A92B" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "32EBBA46F34FE6447FCB9F03", - "extended_signed_metadata_key_hmac_key": "9D457FEC0DED032FCA7C4663788C3413D985458D3B7DD7C77CA808CEC7A7EE23", - "extended_signed_section_aes_key": "C89264716F9ED0AD1A591D4E7B535537", - "extended_unsigned_metadata_key_hmac_key": "A478F927217CE04B52D69110C6FC26C773B68C9CF862C586474F498B38AF736A", - "extended_unsigned_section_aes_key": "726704CD26B963222D3ACE2E8510FDA8", - "extended_unsigned_section_mic_hmac_key": "6912E3F7E93AA50850A908EBEAC4595C5542BD274247902C4EEE48E9EE5C55DD", - "key_seed": "880B555B9AA8600F636A51A179B7E8F577425885545DF12D1CD6E01C87D3FE92", - "legacy_ldt_key": "AFD7043040B31C0F86D1CF833660C533AA297AA161B8D2EFEA77BD0B1A1A2FBE3A194A52BF2950CC1E307695D750E818EB6CF2161FC3C1A0AB54B647FF9275F0", - "legacy_metadata_key_hmac_key": "CDAC9BFD8382DDBB3941D3051353EFCD37015CA03452C66273EECBEFA22E03E5", - "legacy_metadata_nonce": "C80E0C617C7A3CB8D2863481" + "v0_identity_token_hkdf": { + "expanded_key": "4AA95B37D4A63A1DC834AE394C30EFB2", + "v0_identity_token": "B650B408B882856F757A55FC2AB6" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7165", - "expanded_salt": "C7DAAE6B6635A8AB95D2300CB6416269" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B35D", + "short_salt_nonce": "38893FBF7D1BEE182635466F" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "42BCC04B27A64629343177218F57BE0A", - "legacy_metadata_key": "A876ABB90315F25712F38499B85C" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "70EF8C20670E91B0201666736D87FFF0", + "derived_salt_nonce": "135C24DF13767FF03E133BB99D20B0F6", + "derived_salt_third_de": "3B537B5FF5AE9AB51B076C50F88DF467", + "section_extended_salt": "BE300446F843EC41349FC25CBE09D972" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "0F6D736CE65D5C65A3B2D6559F5FD402", - "derived_salt_first_section_no_de": "554244AF344CA2C83F253966F6102027", - "derived_salt_first_section_third_de": "13F1B8E4B07D0A51B509F878A71C50A0", - "section_salt": "FA523DAC59FFB86119FFC29D753AA473" + "key_seed_hkdf": { + "key_seed": "E81B91F6D8C1095C1D42F68DE4CEC8D0976A6491F8AC899966A121D0A6F17A43", + "v0_identity_token_hmac_key": "75C08671B8EC4C5FEB972AA4F02FBC725BF42263C5693DB01E9C94ACFBC4460E", + "v0_ldt_key": "F53EF38DB4429D264B4C0EE8EC671327060BDE5C340F0CAB7EBD0E9C3BC8F7C4A9B49C0CF4A535DB8717F8E308D28FCA5D9ED92D0EB555C3C810C07558772A33", + "v0_metadata_nonce": "7AD4B6D7845B86851A7B4953", + "v1_metadata_nonce": "1AD2218AB0B01CCB1181D201", + "v1_mic_extended_salt_aes_key": "5BAF591B371061B32B72C8E1E56B8B56", + "v1_mic_extended_salt_identity_token_hmac_key": "1EDCEDD0EDC416E7D8DFC2E2CFDFECF6002080DDAE2C1E13AD0E517561621ABC", + "v1_mic_extended_salt_mic_hmac_key": "3041D70D7B869284630A49C8272CAA14F3BA2826BAD8EB8EF3FB2CCBEA2AC1F4", + "v1_mic_short_salt_aes_key": "24B3475C2818DD82B2B861890B521CA6", + "v1_mic_short_salt_identity_token_hmac_key": "17C3C1FEE32642EBAAF0B4D9F769346394FE12D0EF967535CA1AC7C9EDA28770", + "v1_mic_short_salt_mic_hmac_key": "020D702CD9F9FA8D8D4214F4C2E326DCA16E782AB23DB36CD4A846B36312605B", + "v1_signature_identity_token_hmac_key": "CBCD66F3A1395C1C119396056A69180BF48BFE314DC331E78E6B81C06A897168", + "v1_signature_section_aes_key": "7630A756E997DD3EE511628239C2EB42" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "BD6A", + "expanded_salt": "CC3CFE649FCEF543F9D77FC2D14F7DD1" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "2DF7FDECC381703DE06DFC8B", - "extended_signed_metadata_key_hmac_key": "002E77DA262FAF5BEFB7668D09710373FD69821DC3F563320202DFC6F7F8DAFF", - "extended_signed_section_aes_key": "A9B5C0BC08AFE740B6FD1E6BA8220E53", - "extended_unsigned_metadata_key_hmac_key": "2FB80909E593CEDE519FA19B034FFC6D189E0B772B0C4FC686C3732C82B34F19", - "extended_unsigned_section_aes_key": "E8D6F9C80CCF633B9F37574DBC38ECCA", - "extended_unsigned_section_mic_hmac_key": "4A3E71A87ED54DFECD1FC9EDC09371D329E8B231A189D072F827863C3377FD7F", - "key_seed": "B641968304F3D65286618FE936844A883932A98F172FAEB1CF5DC6E77007488D", - "legacy_ldt_key": "9D925DBD151593EAC40F2C7FEA7BE2EC81891FE87971CF1C7F38369BDB8B12EBA067EEA5BCDDC36E5D8430CC67C9F8C85C272E868D75404E64A087FFAB92D7CA", - "legacy_metadata_key_hmac_key": "F8AA867BD12B81AE663E62C650E705DD1F2A1D9ABE38A99A2E1D51EF7E2DA26A", - "legacy_metadata_nonce": "46D5A1760D44590DCE76FCE6" + "v0_identity_token_hkdf": { + "expanded_key": "F3212F08D87FA7C44FCDA7E2C4A0F0C4", + "v0_identity_token": "ED93E5F3F71967B749570A37D16E" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "587E", - "expanded_salt": "D3CDEC97B00233FD542022C2EB5F3848" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "22FD", + "short_salt_nonce": "32484DC7B135A80C39081760" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "0D01ADC26CDE59CB3350AC0374ADD752", - "legacy_metadata_key": "F9664E87F9E82683417A6C69FC6A" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "78CE8B13F129273503E1536058A43149", + "derived_salt_nonce": "C7F3873BDD429C39E5560D733BD3AFCC", + "derived_salt_third_de": "9795B0AC7799E44E875429A7A24B1547", + "section_extended_salt": "F86AB59158954445BC6366F8E823155F" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D2B338926A1201F6CD659AC639B1862F", - "derived_salt_first_section_no_de": "B3E7AA07BD4FAFB10015CD6C196E067C", - "derived_salt_first_section_third_de": "4D84FFA3D9A34766CCBD37DF356A9FFC", - "section_salt": "1D99919B07153CBA8C4D3311A118B9FC" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "F8495F6B16683501AE5B19E7", - "extended_signed_metadata_key_hmac_key": "75B5C62C60C3019BC2D9D4CD91CCAA2E76D33EDC43AD13384123F3B5D52D67C0", - "extended_signed_section_aes_key": "BCC8DB06C53733E8F793BD7D64DBF46E", - "extended_unsigned_metadata_key_hmac_key": "A90E9E7F829DDFB44D1C10AD1BC1BF08401781B8C22FCE5DE73AC6DC0AC66BEB", - "extended_unsigned_section_aes_key": "9F6E49E8CAD1919314298C3A354FC392", - "extended_unsigned_section_mic_hmac_key": "C316406D229A27AF3CB3C13E906287EF8B5036B658FE824A076C8B6E74D2B885", - "key_seed": "BEB2E5288A42FD7AC9E4BE6D4998F32CA5AD102DD6BBF21D9A63E92ECE14F7C8", - "legacy_ldt_key": "7B180A8344D1E4A7E154BDE1DFD16888E3778686A35DCDB75485EF2A93762E0932D6D79EA0826E5ABAF79DEC504B7D539C6324CFF9B7D4C1F19B60B65D3B9BCD", - "legacy_metadata_key_hmac_key": "BE281084F50E511096BF52D7FAA5AE64949796EFAD2615C4FD16495016C5CDE1", - "legacy_metadata_nonce": "42ED5DFB6ABF8FC2CA75DDB4" + "key_seed": "711FC606359D4A42B851EBE5E51877DB08F075A7D54C7F3EA2D1FD4D1CAE4844", + "v0_identity_token_hmac_key": "673BFCEA7A139058558C1767A4466B9CA9EEEE6AD126C437828F22B5C2A7AB8B", + "v0_ldt_key": "4073B6432E80244E5311E22C3E2FA74C303C98CAC85945E276DD8D77D31D6AA6C3E89897D3271C35CB5A4A4D3D744D92934926FBC81CC264DB701F5DF56F5911", + "v0_metadata_nonce": "3CFA4E242A06A8E43E7EB43F", + "v1_metadata_nonce": "98FDBD9939089072019C5C42", + "v1_mic_extended_salt_aes_key": "FF33518D26448E2D4DFA5A67B3B21474", + "v1_mic_extended_salt_identity_token_hmac_key": "3142FEDB54903B750D43E984D94D5501BDF361B27994737A0A77A22E87C2778E", + "v1_mic_extended_salt_mic_hmac_key": "110D45543242D23BD5896052CB4EA44B9DA4AD1B6D6E4D5D795D7F23262FBEA6", + "v1_mic_short_salt_aes_key": "DB686DB1702E76B6A2E835D249E0143B", + "v1_mic_short_salt_identity_token_hmac_key": "4BC8DCD602C7894832F1CEC3D1C715B9EA2DA59AAD81D50108E4CEF6404A92E5", + "v1_mic_short_salt_mic_hmac_key": "BA49A19BBC61BB50BEC6F2C102E4D099DF3D204E3C5CD6C7CEFF4F22B62B5804", + "v1_signature_identity_token_hmac_key": "685A096405A541B4BA786E24DA79E8780FCD448563352CEDF12A7746A7808D75", + "v1_signature_section_aes_key": "737D543B38D9BC756BA6BF8D0E345839" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "9288", - "expanded_salt": "EB04D1DB34235FE2814ABE28338AF6BD" + "v0_adv_salt_hkdf": { + "adv_salt": "6328", + "expanded_salt": "C41E3A15A684898BD69AB353CF9403D1" + }, + "v0_identity_token_hkdf": { + "expanded_key": "C248C7A2DF1596ECF285CD70F0B8FF6B", + "v0_identity_token": "880A532423DC3D24F9B01EB74747" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "703C", + "short_salt_nonce": "C2533EAB891577CD94E07FDA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "E1478A4ABBA0D34E1DBB8440636BA1DE", - "legacy_metadata_key": "3B2669DBE04D22E4146856F24964" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "DD5E5F7DB850DB95FD63F5F6097094CA", + "derived_salt_nonce": "40BF0CC82087F3D8EE4E1070EE4E0D91", + "derived_salt_third_de": "D14D7004CA8C8776275296A563487325", + "section_extended_salt": "B774D26C0DA92679B9F85BA62EF47501" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "2315A6A6A255AFDF9CB9BC23D7481C70", - "derived_salt_first_section_no_de": "2F871D368ECA88997CA4EA877F8BCDA1", - "derived_salt_first_section_third_de": "F4D547600C7C3CC1ECEB4D83C821D191", - "section_salt": "D82414D60C56BC7571AC11EA22FD95A1" + "key_seed_hkdf": { + "key_seed": "60A9A540CBADC6792695C2F83BFF8862F8345D9E52B8356398F78EA5EC5649FF", + "v0_identity_token_hmac_key": "1F216C2E0B900D0689FAC04FA32ACCA32D420E041AC5CAC6651CEC29ADF20FE0", + "v0_ldt_key": "ADFA524EC6DB187734F14812267DD46299AFF92C96CAC67AD898E0C2B51B00BA007A8C226C06BF0A711669687830D4E6A7C8A7E9AF8FA427A91A461D7BA38D77", + "v0_metadata_nonce": "51DCDFFCDEAA8FB85DF5D077", + "v1_metadata_nonce": "B9DE8526EBA518CADE736887", + "v1_mic_extended_salt_aes_key": "BC00D162975B27283A910929DB17F7D6", + "v1_mic_extended_salt_identity_token_hmac_key": "D9D2FA28386C9FCB05171F063FC464630CE1CC52CD47B6B235814B77695DA0FF", + "v1_mic_extended_salt_mic_hmac_key": "55BD72D9FE9ECD40946E57894549E0B468E0A62E2BEC97FD744FAE68C45783A7", + "v1_mic_short_salt_aes_key": "8240C926DD7C8887AB1D99C10D994BD1", + "v1_mic_short_salt_identity_token_hmac_key": "01F8D73775C16E0B2165023A3FBDF31F2FAB14F9269B26E0397D9F75105CB4A3", + "v1_mic_short_salt_mic_hmac_key": "4DE142833A00DC99C9A98AB93893AC000BE38083B7F31F3FB112E93B32B7F3E2", + "v1_signature_identity_token_hmac_key": "2D31AA445FED272EF8CC6C8BD869D30F1F7E2D3D013BC179AD19ECB59DBDA3D8", + "v1_signature_section_aes_key": "4548FC98A94CEB5037232B78069656F1" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "BB38", + "expanded_salt": "DD8BEE6CB4F2F732966A4334D98A6A6F" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "3225229E97DE8EF6EF3738A4", - "extended_signed_metadata_key_hmac_key": "8F2D19779DE3D0BD45A93F9D546C7D70BA7D24A3039FC10FBED142099A7E48B0", - "extended_signed_section_aes_key": "552CF2D3F72D8AD6AE4613521D744069", - "extended_unsigned_metadata_key_hmac_key": "4DD906B20F0F537A4759DEC498B3F5F35A26A850F458B7AF9D140304C138DA3D", - "extended_unsigned_section_aes_key": "E915FB586132C17710BDDBBC7BE734D3", - "extended_unsigned_section_mic_hmac_key": "00FAB34E3EF9BABCC38BB24476583539C41F2C0CA69FBCD21C278742108158B2", - "key_seed": "B835493E7A34BA1C0ED885CF78EB30CED4203067CFB0E3501CF1509C44A10EA4", - "legacy_ldt_key": "63DDFA294943D9D30A1B8A911EF3C9643719AF8B1E30F6CC7FE9EA490E1F5544D22A65721399122A0A6324F215CC2FB178447E5D9F7F54FC326B994C27B257BB", - "legacy_metadata_key_hmac_key": "15C70495ED3FD7EF63650611395B8BD9D6015DEDFE41685077911059081639BC", - "legacy_metadata_nonce": "BBE949BBD59C4F963E7E2821" + "v0_identity_token_hkdf": { + "expanded_key": "58EDE47F3974330EECF1A2E5AC5659BF", + "v0_identity_token": "0848F6E9EEA846D61D0BD7F3145E" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "54C1", - "expanded_salt": "0DB76FBA8F6AC46D1C0E4D3BF4F9760B" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "DBCD", + "short_salt_nonce": "8DC07DE237C5C0973E1F142A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "6815ACAD17F576FCFAC31D7CA348B9C7", - "legacy_metadata_key": "D56BC285FCBC28F14904C110D022" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "53F10F9CA5E77717F922663B49169B24", + "derived_salt_nonce": "4947E98A773F91E71B31C94603FE2A27", + "derived_salt_third_de": "82576C8D1063FA9B9CFE825EC4BC8D44", + "section_extended_salt": "71D1DA2128B0D32EDA53591B8B1E2214" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "A63D90F8D31E70B5F12FA49567853940", - "derived_salt_first_section_no_de": "DBA2B7268B2EDFCE658C2DF7D1F50E18", - "derived_salt_first_section_third_de": "923531B496A572D8E6C45ECDC3598D78", - "section_salt": "228003CED4DE76F9E2E12998C3ACF2ED" + "key_seed_hkdf": { + "key_seed": "DEC336D867DC86E9DA91F93D9F113D8A99EC2AEEFA5DD7076B98CCA93B775711", + "v0_identity_token_hmac_key": "36AFC7B183AF0C8815E337171C0F2B1ED7E3CC03C462D8360D86A9FBE61F763D", + "v0_ldt_key": "9A045E5092D0802835C2D77F9AE24B0C6572E27E10734AD0D7472C087E5A5BB1D94FA44F1094BF3C77640E483C4798C744602EA06658E401F3DD13DB5E9F2978", + "v0_metadata_nonce": "02E64EE4D3783A3B84279BCD", + "v1_metadata_nonce": "3BEB93AF74FF27D9CB898AB6", + "v1_mic_extended_salt_aes_key": "A981814F6939740E0FE916C93350E687", + "v1_mic_extended_salt_identity_token_hmac_key": "11CAE48A1DEE7B9BF057D721989DD4D6EC5E3BC7057B572EAB0EC91EC246C51A", + "v1_mic_extended_salt_mic_hmac_key": "2827D2973DA029745965B868ED9634EB7394D442143E79E72CD09BBC9F59F0FA", + "v1_mic_short_salt_aes_key": "5013ADB5508464143F2D2A96C807E459", + "v1_mic_short_salt_identity_token_hmac_key": "859EAD154B93576E407471495FD37A54193F9CFEE0078342EF48F677E2A20AEE", + "v1_mic_short_salt_mic_hmac_key": "2C5C56B063989DD245791D8398E146A585C4F91C8C29240814E606C0AF4CB6C3", + "v1_signature_identity_token_hmac_key": "A7A0CF65D8121AD48101E5A10512CC09F6B50FC64142A030188B6ACA57EE2219", + "v1_signature_section_aes_key": "2AD28911FAA0C9D0FD4295ACB09823F2" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "C6E5", + "expanded_salt": "77DF9D9647500CC9FD17BDB3F4E68BE9" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "9D7BBE2671E7D6C30CD6F810", - "extended_signed_metadata_key_hmac_key": "33EB25BFFFC7B15197FAEB32C928CF5A128D01D00735C3EF7727F1F761F51BAE", - "extended_signed_section_aes_key": "7D5EE6F4E07F8C5F07E258ECD20D4D34", - "extended_unsigned_metadata_key_hmac_key": "792E4F635AD3FD8AA5054F8EC58AADF6BDF7471EDF9EAA2445C944C3C10B6463", - "extended_unsigned_section_aes_key": "9DDB1E227FD6E4F9FA7D29BB7A5A1C4F", - "extended_unsigned_section_mic_hmac_key": "9611D448338D20F3C6A6464C9CBE3841CD703E6FCBEBAC5EB44D3F5F5D6997B4", - "key_seed": "D116B27178BB5F9D9979CBAA97159E4D4410DE3D26CE2AC3ABA7BDAB63A6B85B", - "legacy_ldt_key": "5628DCC812A21B82C0619D613EE0E4B67082C89E316D23EA3409563EB8E297377F472FF25C4A0A70B2889BB27293873724B8C0E94A83D9EE2E080D3A5CFE0429", - "legacy_metadata_key_hmac_key": "76D7B1B4B3E7432884C9A49F46FF26F1DCE8D583344AFDC7A6635254EEB5CFA7", - "legacy_metadata_nonce": "3C2CA3B55509876DACCE58B2" + "v0_identity_token_hkdf": { + "expanded_key": "920EA91C74EF23E1607E7112BD9F5783", + "v0_identity_token": "190E0DD127CCE7E0A7B69779408D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "A386", - "expanded_salt": "F59E3504B2B86D465989D0F5B5F04E7A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "BB49", + "short_salt_nonce": "063DDF6B3AE8F83186DF04FA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D4522DEB87180CBAD14338BCF3B1107E", - "legacy_metadata_key": "F1A6EEEAEFD437330DFB706FBC43" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "64F5ECC15737A6BD0CD7148884A7389B", + "derived_salt_nonce": "FF7ACEE09C30922CC4367ACD2014FBE9", + "derived_salt_third_de": "A4B5B9D6F05A84BC5AA915AC954CA94C", + "section_extended_salt": "2D31BE7AB1A84EDF74D9B66B6DF3E7D4" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "06C173FF92776658E2DB2394907E31C7", - "derived_salt_first_section_no_de": "CC2D079DF426A5359DB15CF4DF6C894D", - "derived_salt_first_section_third_de": "5FD567F78807129F25151725F939CA7A", - "section_salt": "375DB6FAE577F7F2BBB1483161B62D98" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "4DB0F75206E7B33C55CD1A87", - "extended_signed_metadata_key_hmac_key": "F01DA0E7048DC47AF21AE6E1E00705711F397C80E4E5872FD484CB2A353EA84B", - "extended_signed_section_aes_key": "EA0D9B928C271079D8DE740792217A2E", - "extended_unsigned_metadata_key_hmac_key": "0FE25C53F513D8C4079663AD26D3EFB76C9E53403A32CF3DD1AC5C4F0B46D401", - "extended_unsigned_section_aes_key": "BEFF54630EB0851BABD6C9080B3650AB", - "extended_unsigned_section_mic_hmac_key": "41E49DFF047BB3D9DFEBB5D86CA2FED61CCA22A8DA4AFE08010B4B2E026605DC", - "key_seed": "8E94D64DA399A2EF9428419B72C2D6B96EBD83470CC5894564DC624BCAB5F437", - "legacy_ldt_key": "2B802CC087114906FA80A9C68E0991C1D99CAE898EF25F2EF7FEC84E4B8F194AA4608F022C7912B8879BADAF1689140CB37BD15C4646BE36C61CDE4199AD27B3", - "legacy_metadata_key_hmac_key": "290F16A7EF5A15726241870605899132979F304FC452B6E7D3CB80822AE3DA7F", - "legacy_metadata_nonce": "9FDD6FDAE7D43E1937EFD1B8" + "key_seed": "D91552CA6C061EA51B80DDEA22465FDC3B0254D5F3D78F066E085A2711FE31FB", + "v0_identity_token_hmac_key": "2C3247978B974787D1F1037BF6C69B2F65B26B74DDD33F83EB397BE7E17B5FC5", + "v0_ldt_key": "2FFE770039FC6E6C2CCBA99EAEB23A3788FDEC93C54EA11CEC0E3CF8158FD17614CEDD82122608FC93B4831F1FB8AFCB724FA79F5F8013395D0B20273BC895BA", + "v0_metadata_nonce": "681F0C626EEB0EF9102F02CA", + "v1_metadata_nonce": "ED7B5E3B33DD153551E7EDFE", + "v1_mic_extended_salt_aes_key": "6E2FB2E25A3DE00492B7D00564EE4B9A", + "v1_mic_extended_salt_identity_token_hmac_key": "6FA4C0C757B012B5475EE27B9ECB13D0DEB28B11E050E62084099848AECABED0", + "v1_mic_extended_salt_mic_hmac_key": "5F0411676B1FA1C17C08568A88BB477DA9C2016560888D6D791D342CA8C9B812", + "v1_mic_short_salt_aes_key": "AC6C5BDDE8C655C7354206D748065E45", + "v1_mic_short_salt_identity_token_hmac_key": "7F04F2F8BAA4D0F564D291E17E00A4EA547A33D22C144608D6CA64D048571502", + "v1_mic_short_salt_mic_hmac_key": "6E2F84D1A9BE9234BBD6F8138068B7520B8E056B1B0949EEA5B720972DDA5D5E", + "v1_signature_identity_token_hmac_key": "983863BD77F0A3A79443DE302AD320F51EDACD4E735385260CD8703414AC897A", + "v1_signature_section_aes_key": "E62E81BBD49561DD9C20FDD414C1BF8A" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "1161", - "expanded_salt": "CAFA25E3F8E00053BC3825E8FF5D5078" + "v0_adv_salt_hkdf": { + "adv_salt": "C20B", + "expanded_salt": "20C6AC9CF63183FE2C3578F69D5E81CD" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D918D076ABA54A6B7FB5406522616208", - "legacy_metadata_key": "6C7A1A6D9A337FD3FE62B2E2ADF9" + "v0_identity_token_hkdf": { + "expanded_key": "4E76651BCC3F7AFDEC8631FB3156CA56", + "v0_identity_token": "70DE62B41AE48BFBED5AEF89B4B2" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "FF14", + "short_salt_nonce": "9EC52904170660BFC9946FD0" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "D3DFF59C7AEA3C8E820B92E76B80ED03", + "derived_salt_nonce": "16DE3412C96734F65C24B77E6A597BAA", + "derived_salt_third_de": "73FC3E0306353363F7AA4F8910C1F86F", + "section_extended_salt": "F0181D6CC67C40620D61C0377D06627A" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D2C405851BBC1268709BCA5E92ACB57B", - "derived_salt_first_section_no_de": "8F84A4AB6444AFD08FE7110D0D16C74D", - "derived_salt_first_section_third_de": "4C3C84632D69672E8921C5067A7DFB56", - "section_salt": "5D950CB5E7D9F44E9429359415FED1B4" + "key_seed_hkdf": { + "key_seed": "D6B3A8F4CD3E869B904A4B1F0E34AC2F37509D40592A3884C3E69067632ACCEF", + "v0_identity_token_hmac_key": "D27AD5EC8129C043262F5A6F48B2B1737A5DDB08C6205D7D7CDF0FD8BF9D87B8", + "v0_ldt_key": "3B685DC172EFD153B0C6875F3E52B565A97993C96DC3FDB476E47A0945AE33B11B47AB78301330A079D7E68E6F89925EA528BED0EE437053FA1C0CCF9C294059", + "v0_metadata_nonce": "D3F45B2A2A8330C89A0D5A8C", + "v1_metadata_nonce": "3FD567346D88B78F94C5369F", + "v1_mic_extended_salt_aes_key": "E01D5674316E8357CB925409DAC3BE13", + "v1_mic_extended_salt_identity_token_hmac_key": "26EA66B124B9E03456EC07CEF36D6A24F1CB985CCE9F8285DA4139547D71B341", + "v1_mic_extended_salt_mic_hmac_key": "9EB1CD357FA7BB0AB5B17E95661DB20F30A9AF2DE76F06CDC6FF19D4B533A15F", + "v1_mic_short_salt_aes_key": "949AE776AA4D9F7B80E23D25EC3F0CB9", + "v1_mic_short_salt_identity_token_hmac_key": "58B69B49CF4DB03F5784823D95C94E868AFE1B1AE547131F32A0410CA8B4C205", + "v1_mic_short_salt_mic_hmac_key": "166A695C761FE5D1C0CA5577CDAE59BADC4D6B34ED6A02FF8C7C5B9F9D829D34", + "v1_signature_identity_token_hmac_key": "B8A5017381D6CA6EC9A1CB4676F00BA3F3F345BCA33C348CB7CE60AF1A9A7279", + "v1_signature_section_aes_key": "8BF7B8345F2B0BE8DB7CBE7E96D9E3AC" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "F061EE619FB13FE95DE267E8", - "extended_signed_metadata_key_hmac_key": "F276A731C51D5936687E7F908F88224BA28BDC2D6A4F94999765822DEE917D6B", - "extended_signed_section_aes_key": "CD9E5F7C922F58A56A17CB8F62B9DD09", - "extended_unsigned_metadata_key_hmac_key": "174295A2B19CD4F9A821895D098CC63CB4CF17AC16CA7BD0DABF7136C2D3D194", - "extended_unsigned_section_aes_key": "1CEC9AA427A98480A6642003700F4A5A", - "extended_unsigned_section_mic_hmac_key": "6780C7E76F1A85B3E31A1382505FE21BA04AAFE268C9810C626E72C9203C638E", - "key_seed": "234DD6BBDADEA172BB97EA68E22A0B0321F8DBD65EAAAA38F95940D73770F35A", - "legacy_ldt_key": "7E7C646B51F1867F6D7CEA56F2AC7EE80DE9D9DE2015E9CBD7525ABD0FA05656CAEFE120EEEF521CEB7D9E296555CF8A249862D97F0D3FCAEDE9A4E8C309092E", - "legacy_metadata_key_hmac_key": "1DA50172EAFA031A15FADA0313BA770324BC8A0D1223FD5EBC127A331459F2B2", - "legacy_metadata_nonce": "74C72A883D6BA2CFB5F68830" + "v0_adv_salt_hkdf": { + "adv_salt": "30D1", + "expanded_salt": "F75AF6269831BE87E645A48C8F2731FF" + }, + "v0_identity_token_hkdf": { + "expanded_key": "8057B45E2557983E5B173883A75396DC", + "v0_identity_token": "963C9D4D52A09EC1EC5BE7FCE09C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "F836", - "expanded_salt": "F8809BFDD69EE831A7686D8359BBBAE4" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "AA48", + "short_salt_nonce": "3BE65DEA17A00BF9D49A1C38" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "A97B037072AC4D59472E20AE1C8688CE", - "legacy_metadata_key": "4E18A6F5EEDEDFAE9AEE43A53094" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "2B99B7DBFD1AD40DBE93E10E259A6188", + "derived_salt_nonce": "FA549B59FBB527C1422799C1749F0304", + "derived_salt_third_de": "7570E91C96332E0248AB19ED32AE2A31", + "section_extended_salt": "0F3D3F0272988D59B1F3B1C6189E7E89" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "146332F0DF9B6701D5F6ED9173B966D7", - "derived_salt_first_section_no_de": "CA5CEB6D8BA41402859B0706E603C25D", - "derived_salt_first_section_third_de": "E93B2C310878FED27F89298CA9F77731", - "section_salt": "EB9DA18BDB815DBF4BF9906E8AAFB491" + "key_seed_hkdf": { + "key_seed": "CD466940D42BCF990370FCB55B63201CDA22DCA5BBCE0CF1DDCAE350E8B085E1", + "v0_identity_token_hmac_key": "683039034AA4C0DCEE3755EA41EA4A3DE983519B99FB961E8E8ED53FB4A96483", + "v0_ldt_key": "4FD74D82D4A29FE1254412C2A8FC74CDE4A10F3646E3CE11A4B34FBF18D8FC0B50597225A7BDC05FBF9791050298EE47ECED684F9404BC82CAA00471CB18C07C", + "v0_metadata_nonce": "B15E214FCECA2AF6263F0071", + "v1_metadata_nonce": "2B41C0A066C4E06435814541", + "v1_mic_extended_salt_aes_key": "849E8DED91FA247EC22FCE659E4458BB", + "v1_mic_extended_salt_identity_token_hmac_key": "6709E5FCA4295FD242F0EA72816B18EC308677791291539D458CF0C1BB3F2F09", + "v1_mic_extended_salt_mic_hmac_key": "A0CB3B5F81BF78216E18957A46B0DC4E38570FE1C69B1D6E06D29C3E2D56C5CC", + "v1_mic_short_salt_aes_key": "A67440D7A821523A84FCA1633161125E", + "v1_mic_short_salt_identity_token_hmac_key": "7DB92F89448C4D4059E48D199C36ACC879F0E450B0D8EECABBEC8C387B6A160F", + "v1_mic_short_salt_mic_hmac_key": "5378B75FE4E4A8505FAA231CA43CB0DFC1BFB53D07FFA2FC61391214AF21D293", + "v1_signature_identity_token_hmac_key": "31F296D8BBC8E6C8D877190FF808746B522B781F5D98E234DE608194E60A928D", + "v1_signature_section_aes_key": "C1E5CF90392F864D15390E483F08562E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "588AB130BE0197CBF1E240AB", - "extended_signed_metadata_key_hmac_key": "948A762DFB558385CDAE56420D2AF863F8AD6ACB9EC442775C20F1D12793D08A", - "extended_signed_section_aes_key": "FDFA11ABDAC005CD0C6DBAFE22CB84F5", - "extended_unsigned_metadata_key_hmac_key": "A8ABEFCD7AF7D09F7862E825FC5D641A23CF32210676F1CB8AFD375F180DE059", - "extended_unsigned_section_aes_key": "895814EEFA0514080381B2466C5560DF", - "extended_unsigned_section_mic_hmac_key": "770CD91393852E19BB1A5878B8BDA5E4B9AF9A0640856804C470EDE355DB0914", - "key_seed": "519521C296DA4C8A13A47835506AA306C9782F3F1C946D061616CA248E64CD9E", - "legacy_ldt_key": "84406D27E7717B520A082163CE7DF98BCC0261E8342C105F210C31FDE6B5521547E51414E67D00BDDDB57046564FD491A88E4C5CB913D28FDA7C972EA21A9DA0", - "legacy_metadata_key_hmac_key": "24032DA88D3510F18FEAF898A414BCCC55EF1E56350D07B6A4AAAC85AD09C863", - "legacy_metadata_nonce": "F0392AFD52B25E66D0D16B50" + "v0_adv_salt_hkdf": { + "adv_salt": "82B1", + "expanded_salt": "1BE40D25CD9776534A2DDB5611A72A24" + }, + "v0_identity_token_hkdf": { + "expanded_key": "902BF2B1A996C43B041F9B420BC96648", + "v0_identity_token": "E51F72D506023394F7291D484052" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "AF9B", - "expanded_salt": "488FC6BDA553D9894C6C397E009D56F9" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0C5F", + "short_salt_nonce": "408CD97C38B4878C593CA9FF" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "AF67A28D0088401BE912DFF010C7CD2B", - "legacy_metadata_key": "0A0692A83815A72C28C2E1A0C324" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "2CB4C2F731719080646D748288FD8A09", + "derived_salt_nonce": "C65251DDEEE83B1C0C7B1B6417EBFAA3", + "derived_salt_third_de": "E3ADDE6C9B9124A4ABDC4026178DCBAF", + "section_extended_salt": "20638EE0EBF0D34A51A53EF7563C15E3" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "B57FD4C4A95B5FA80E77FB0A4342B558", - "derived_salt_first_section_no_de": "804C7287DBC4705759D1543D3BB19796", - "derived_salt_first_section_third_de": "185B5BE5742AF28DA4D9BA8FFDC8E609", - "section_salt": "1D6723044D269740F2E422789242AD4A" + "key_seed_hkdf": { + "key_seed": "BDBD1DD888D7FDCF43BF9D7F6674ACFF1DF2E2C660FBC745E43313739FAC437B", + "v0_identity_token_hmac_key": "FA13440C9B6024C2DABA4BA5D15F00E2366B7846D588199DCB58B38C1C6E9922", + "v0_ldt_key": "BE949780CD96A922B71160362959CE07376AED81979109E62E5BBB877A85E6C4EC0414697132AF7771485206B9BE8672D947996AB8878E479DDB3A29AE2C2373", + "v0_metadata_nonce": "7D5D37D4DC2C957A04376DA3", + "v1_metadata_nonce": "6131D2EB386B29CC1F335147", + "v1_mic_extended_salt_aes_key": "04B76123C0DA3C10F84D5303240799FD", + "v1_mic_extended_salt_identity_token_hmac_key": "536A471425BF8B929C332DD55423F010A15B4290CD453E78E4D53EE35E285E96", + "v1_mic_extended_salt_mic_hmac_key": "B151727B25FF7630AACE3803BCB85CB942EA1638E45F1DFD70663D8B8143A6FD", + "v1_mic_short_salt_aes_key": "266FAADB0647BF79A759C9F747F0236B", + "v1_mic_short_salt_identity_token_hmac_key": "F4C7A6A7F8F6FE6C77AB0A95A7A716966C7828BF5E7D1A7204984823639ECB20", + "v1_mic_short_salt_mic_hmac_key": "3EEF8D8F921DEBFC0B38B2C969488FC7EEAD618EEF189F0D6EE427539133095F", + "v1_signature_identity_token_hmac_key": "0B4E8908F5113876B22700FD9505474EBC4FAF369F850F6FEAB2CFFC8C218857", + "v1_signature_section_aes_key": "BAD090C852284E25461B7152B1B4D5D5" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "3345", + "expanded_salt": "F64A0AF0402F5ABC4D541C1DD1FA7C89" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "E4EDFA97754C39393AEEF09A", - "extended_signed_metadata_key_hmac_key": "AE6C660ACBE3D637F9D01CFB4EA927FF4B1DEB1446EB096688BCB54F5C1A5389", - "extended_signed_section_aes_key": "DC58AF65EDAB2BDB393DDD7033F781CD", - "extended_unsigned_metadata_key_hmac_key": "578C17FC68D03B2A9FFA8352C4ECD9D15DE2F97B5500DB4A9FEE70A93E28AD2D", - "extended_unsigned_section_aes_key": "573CC36574396A27D5CD12DE72470637", - "extended_unsigned_section_mic_hmac_key": "9D8CFA87DB083EF2FC4C495E6A7E3F8483C608A186AC9EFB6C22144B4A654034", - "key_seed": "A34102D098DBC12FBAAFAC0DE0F0959450DF888C7323AF55CF04B976E6B9152C", - "legacy_ldt_key": "78065CCC471C92F1328DF45AF7180DCF3073A56F599B861706DB9691DEE1580AAC1FBE1215CF24AF403A0BEA04E27C87E91E24DE63CB61C35576326B32A50F97", - "legacy_metadata_key_hmac_key": "E8B03892D17EFBAAFC23A96ABEF538A2AC1B34A9A76E5C32E70D67CA73491EFB", - "legacy_metadata_nonce": "889DB55C293C1227BCFA48AB" + "v0_identity_token_hkdf": { + "expanded_key": "D6DA7B5AE8C730D4E0C56F0D2F3C033B", + "v0_identity_token": "155B071F6DBF3F06763299B0DA91" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "4644", - "expanded_salt": "8E7143D60063DC6AFF6A285C0CAED64A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8534", + "short_salt_nonce": "7F613AC000317D4C02D5D869" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "B61F6E359C97537CC9B30A51581DCAE4", - "legacy_metadata_key": "D3E6FF7D90D25CD472C672173992" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "C9C285BA4E31877EB2B2E031CFEA0B30", + "derived_salt_nonce": "35A6A82C0B520C126652A1376AD58DF4", + "derived_salt_third_de": "2EEC85204A794C280C774C8F2C037204", + "section_extended_salt": "EC6182A82E58AD95A9EDCACA06791FF7" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "0CA731695CA701A5DA7CA3F15898E7B4", - "derived_salt_first_section_no_de": "C576F3146312E1744C5AAB5553880FD8", - "derived_salt_first_section_third_de": "39E3A93EEE518127370FD04B92CA2506", - "section_salt": "DC536229ABCC11D225875AFE64B192BF" + "key_seed_hkdf": { + "key_seed": "307F26401920ABF523527895C6DD0F6BF4B20773505B1BE846B0D048F5A6FA87", + "v0_identity_token_hmac_key": "17B4D37D0642C6716EB50B800D65C3410F8A04F34927CDF15275E645C59D45FE", + "v0_ldt_key": "09BF32231643E1E288D213670302BAB93CE75A5733953005A01478F7A1B8740B5B08277F5A62B3C82F55AA5417E71E5FADC2AFF385B8683DB86832B0735ACC01", + "v0_metadata_nonce": "615BD483D3F879E35D3CA43C", + "v1_metadata_nonce": "147E38826C4682E5AA5E1678", + "v1_mic_extended_salt_aes_key": "2212A788DC4EE1ED998A958A0E4733A3", + "v1_mic_extended_salt_identity_token_hmac_key": "D28E7D6BDAD5F4C6B2A9FF58DA57133DC92F4C34F60DC107528B423361DF5493", + "v1_mic_extended_salt_mic_hmac_key": "95EE789B7EE2D188C993872CD7F7928AADCBDB063EF37B9BF4A1E42FE48BF27A", + "v1_mic_short_salt_aes_key": "FC2D104399AED84B2E04C6EC5B1D6434", + "v1_mic_short_salt_identity_token_hmac_key": "C378873BBA5D9686626014ADB68EA7DE71CC905C6212AF0D8659D6D6FF2D364B", + "v1_mic_short_salt_mic_hmac_key": "954651192C31CDDB288CB209E9644C9BF38566DAA16B828AB8BA51B40760C5DA", + "v1_signature_identity_token_hmac_key": "77C78656128EDC316410216D4A7ABF39E9A83F5C975B4C0672F4FBA61C855342", + "v1_signature_section_aes_key": "AF94A29FB78A0FE335FEC5E8B5C8DB93" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "5094", + "expanded_salt": "D74D67EAD97A17C8E712DAFC65DFF5FC" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "D28B1E59115D3A1862CA1F90", - "extended_signed_metadata_key_hmac_key": "59A3E079DC5F8697219BEB4ED10CBD2BE60551E59B9FC30296574304026D05D2", - "extended_signed_section_aes_key": "15491B6EF07D98836A01228ED8225758", - "extended_unsigned_metadata_key_hmac_key": "ED9C566500737283B6CBE3288D119DC773E50C22A2736E0F95F6EF4BD583C67A", - "extended_unsigned_section_aes_key": "FE8FBBDB0EEEED2024B35F30E49E06B8", - "extended_unsigned_section_mic_hmac_key": "24EAB7D66302B766B2BFE287A784673467022D56E7A4706B3EE7BAE1A04787FB", - "key_seed": "09A152AA290EC4BF418AFB60B3F66BE866078A5F59FC3BB39728DC80EFDDC5A1", - "legacy_ldt_key": "E3265FA3C650A2F0DAF5CBE890CE5430807AD6C7E423858F4D8A47DACD39BD87C5439DC6D952CF87DBD0840736D5FFDF0EB5FE2661A9141B2CB3C8B28DBB7F77", - "legacy_metadata_key_hmac_key": "6497FF0A4F742EBD8C908673D696FFA289C2C1DB64434ED082F9D2C7D8862196", - "legacy_metadata_nonce": "21BEB33970139E57B2BB897A" + "v0_identity_token_hkdf": { + "expanded_key": "79BAFF7725786B619730FB1B5E660879", + "v0_identity_token": "03829BDD7852E472F79492371156" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "DD89", - "expanded_salt": "0F01369801DE549FC4946F13D754CCE9" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "F32C", + "short_salt_nonce": "EF90714317133008CC791097" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "EA4CA525B09663EBCABF017A6AF3FE89", - "legacy_metadata_key": "0D4C5F0560894C41FA9951DF6EE3" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "FC45A7467A362CB4A7BD1B51717012AF", + "derived_salt_nonce": "DBDD7802D5F950078856A9182E623962", + "derived_salt_third_de": "3C2970E4D337BA8D15FB3CEB02305027", + "section_extended_salt": "6C61349ED1E575BEE8632E0704C63FA0" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "621132026D7F9CCCF26A682B7761183E", - "derived_salt_first_section_no_de": "24DAE7CEF38D92425B0C2C94B88566BC", - "derived_salt_first_section_third_de": "813BBB1469B4319669B8093FC8FBAA15", - "section_salt": "42D31FE0C4495AB88C2CC34728DF59B9" + "key_seed_hkdf": { + "key_seed": "0E57BC7F84E2B88D3E6E6DD1550544428123BDCE8087A273CEF083D508E9CBEE", + "v0_identity_token_hmac_key": "07AC05011C6C5798F10523C178095F30D09C5970D295290BA1C149A8296F0087", + "v0_ldt_key": "991B35604C8E261E12252B7EB4A4B5E7AA5D1E282346E35ABC119F740B72263B25F5CD970591A5A691C44930A6D53D17EDE0E6279C0811AD7F95BA846959125E", + "v0_metadata_nonce": "662688EA68FB63CBED7727B4", + "v1_metadata_nonce": "C34766435CAA1EA79616B2DC", + "v1_mic_extended_salt_aes_key": "D6A8080BBF67B2A5F31F50CC3F065D98", + "v1_mic_extended_salt_identity_token_hmac_key": "0F61BEE5E9E628D2E6AE6BA85FEDE8644C0F7A67913C12DBB7A9A2CC0F8003C4", + "v1_mic_extended_salt_mic_hmac_key": "54034D6726FE5EB1B3ABE64CFDA9F59B27363AE3E31134381439AD97E9D102CF", + "v1_mic_short_salt_aes_key": "563BE2F028CCAFACB90F495AB1C6E90D", + "v1_mic_short_salt_identity_token_hmac_key": "179DC9E04EF5284CDB8226A46355E771C618934D46052339E580CFA4A1042921", + "v1_mic_short_salt_mic_hmac_key": "65238FBDB477D87AA79E6BF2FEFE763D26C95FC2BE480C007318A1FE0A2B2F87", + "v1_signature_identity_token_hmac_key": "8548488B07F32D86F41B584DACC3FAA5D1FBE99B85CA152CA358C585D27E8C05", + "v1_signature_section_aes_key": "649A99512E6B524CD6AAFB9349EEC4AD" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "99E72102DE2485A8CD026DCF", - "extended_signed_metadata_key_hmac_key": "49534D2085653D32DCBD06492CE860375D41A3D91C5517D98759257E6D22D46F", - "extended_signed_section_aes_key": "F7091AD2941314A7934D2C74D2D2CB35", - "extended_unsigned_metadata_key_hmac_key": "A0BA2094C1CBDD22854EB846FA4DDEC387B0C1E13A7BB833C6E7110ADA47F6AC", - "extended_unsigned_section_aes_key": "ED03585313F4DCE95E765913E100E591", - "extended_unsigned_section_mic_hmac_key": "EC361DD6B444EAED4BF342CA6479319B2FA391062D6E627A50F40730EFC50B5B", - "key_seed": "154EB89F568C5D04EDC4AB0A61DD783D0EBF04437A188B2175B495C8D5019655", - "legacy_ldt_key": "171DEF9D37747E6F9D6BBABE17B2F7E049608D67518DE48445AD0FD1901F6016C95AEFBE451AE7E256541B8307A16A7E0B7D259219DC81D4985EAA3FDB743E44", - "legacy_metadata_key_hmac_key": "9BC8F5BF79FD354DAE71DE2CA4B91AAC36D6A875D3287D721D3EDB4AF52AB3C5", - "legacy_metadata_nonce": "A5C09B3E1E02FC388CE5D124" + "v0_adv_salt_hkdf": { + "adv_salt": "BD68", + "expanded_salt": "332DA8CBB87E4B90D053E1463E6E25C6" + }, + "v0_identity_token_hkdf": { + "expanded_key": "889AA04ADC0A6867A691A37458CCA261", + "v0_identity_token": "CA3D2CDE92558D49C685F9B8DFDA" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "42AF", - "expanded_salt": "D2BB747C495DD8231531B9149C9C866F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "002E", + "short_salt_nonce": "268B4FA03588CAAD663128E5" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "7831F6B9B71D322F74FA91734B8C193C", - "legacy_metadata_key": "6C33C973C499174E058F63F0D59B" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "3BB392471E3DC9FD55124F895C7715FB", + "derived_salt_nonce": "D55F2D27065CEC26BA6A3CDA4A99420C", + "derived_salt_third_de": "F0C487B8010500EC28E1E162C3ECDA7C", + "section_extended_salt": "B6B17B39F5C7EED0037906B686AD650C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "3D772AF59FA77F172C0C61E75864316A", - "derived_salt_first_section_no_de": "45BDC255A9DC922C4D816CE216609E29", - "derived_salt_first_section_third_de": "C7256E328AFE8C6ADAA9007494408E01", - "section_salt": "3AA898649E58CC9FB5D7CC5FC9B26C7D" + "key_seed_hkdf": { + "key_seed": "625636745F59A39E26742EB6DF2271730742517E40EB51C3959C5D2F4D70A530", + "v0_identity_token_hmac_key": "0C8AC8EF01326F2AD11E8858B69A43B5F4B6B47BC544439D191CD8D31B5B857C", + "v0_ldt_key": "0DE470CD371D7AE3F4866BD032BACAA9D7C6704BB978CA8F8C5BAFAE165B410130422C2B4E224A89F436752B8132056C26E1ED10ECE94DF85D223933ACC7E554", + "v0_metadata_nonce": "5FC268D65631597D5ACF7E03", + "v1_metadata_nonce": "75061912973730B3C8F98A6C", + "v1_mic_extended_salt_aes_key": "5F0F57E6CD52CCCCA1454153370C730B", + "v1_mic_extended_salt_identity_token_hmac_key": "C7E773D20038E16FA0BDC823C470DEDF88C831B8D9E57B833BF5AEF29F3609D3", + "v1_mic_extended_salt_mic_hmac_key": "88229AC78E07751043236D0963BC121E2A4EB6489D0C19008E3210F57277CD90", + "v1_mic_short_salt_aes_key": "8C3C9A5E608DDD8195590F70B852C9EF", + "v1_mic_short_salt_identity_token_hmac_key": "9D1C4285C18AA6B490C11557CAD4A909ADC0711EB5F0FE493D0A837B84DB9E1F", + "v1_mic_short_salt_mic_hmac_key": "95550CE1FF69EAAF1BA1E8AE6560F29F2E068D0C8C78EEA78A6BB8A898B09C83", + "v1_signature_identity_token_hmac_key": "3893648367F0710E2E1FD4608C7A7892DF05A40CE1DA124C99F7483016B2A9AC", + "v1_signature_section_aes_key": "9E4A0F1FD50A640743596D58FDAB2A8C" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "A14A", + "expanded_salt": "6EB825B90A6FA254A206AE337AB5519C" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "EAA31B86CCF3CA56AE358D43", - "extended_signed_metadata_key_hmac_key": "52DFF69B372CDF7A4E4844CFF34AFF3B97EAEFC323FD0BFEE409062D8D283ABA", - "extended_signed_section_aes_key": "51AE16500538B6819A646EB9AD330FF4", - "extended_unsigned_metadata_key_hmac_key": "8772D7EFEF2CA10A882DE8F73A4F5949575BF58E5293FEA863ACBABFC7E12EAA", - "extended_unsigned_section_aes_key": "70847AF7A37D9C84957AABC667F6F066", - "extended_unsigned_section_mic_hmac_key": "5E659C4B61ED807910D78AEB440F13CA494228B7F0332854B2D54C984254BFFD", - "key_seed": "314E89C6DD5D18FE4B824727DFD96F2844000FE144F0BB3AB004B4A8584DEA1C", - "legacy_ldt_key": "4E0F8B2D2B62F991AC23EEE229F133DF03674A412318DAE3B7D31B1EB3F5FC1394FBF81FE0CC0088C08624C058F8A4F5069A6B7DCFB26B2C24F59FE8999EADD6", - "legacy_metadata_key_hmac_key": "F3595FCB9F437ED53C7BB6D2A52EB890BCA1D8B823722383D76830B50E58086F", - "legacy_metadata_nonce": "BE5139909CF99938E465B5F3" + "v0_identity_token_hkdf": { + "expanded_key": "F32FE88F6A32C1FB8D6A7936DB0D701D", + "v0_identity_token": "4D181E23F8727578CDDFFE6C0807" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "E9D7", - "expanded_salt": "8143B10A7353AFD1884BD8652E38C1A1" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B4F7", + "short_salt_nonce": "689506D55DA43C98229E35E8" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "22B61200D9EEC2A81E8FAC74ADF6F9E6", - "legacy_metadata_key": "6EBCAA307ED2B72FFD2CD6F249C5" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "6C28C3ABDE8FFDA08F9953CB6B24320F", + "derived_salt_nonce": "410E75A3CA41E3C125C11FBB5FEF5698", + "derived_salt_third_de": "7A39A6831FE1C42FD179D229AB3BA997", + "section_extended_salt": "50BAC8BFC5B415D834FB0E214FD0A435" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "9D4357DFBE20C028112104A515ACC3E2", - "derived_salt_first_section_no_de": "A23C5D2DB650AD57227C15A86F1BF40E", - "derived_salt_first_section_third_de": "7A4B1899973D71DDCB4F92E1665072B3", - "section_salt": "68C6FD12C8C56CB58DF60455A0FE7AD1" + "key_seed_hkdf": { + "key_seed": "19CC012CC9001734B8364F869F1A509B73FA8136E244B9D3B748729B34A79FC1", + "v0_identity_token_hmac_key": "91126F93E7F6C136D0C45B2F4ADB05E90FB2820050C1AE0661268F615D656B50", + "v0_ldt_key": "65E151200435492E2E08BF9BD546BB5E874D98423E143068353AA241C017C996E11ED54A21A0E0271119A64E347B1F3D2A677F102025296C9AD99FAE60526944", + "v0_metadata_nonce": "AF7153D5E3454D574F3AC87A", + "v1_metadata_nonce": "B95A9D3509FB843EDCDE7C30", + "v1_mic_extended_salt_aes_key": "858513A0BD8CA526CB01C37D872CC17F", + "v1_mic_extended_salt_identity_token_hmac_key": "93C55B03439CB5070EB21AE8A4CA9BBA65F3B5455639ABEF55BA06D9DE5D097B", + "v1_mic_extended_salt_mic_hmac_key": "F62B10BBE49EDB6710E99F12D0A7A5C4F76E05158905098D3B7E7221675057A4", + "v1_mic_short_salt_aes_key": "12A98E8CAE6329555EEB63400A56D627", + "v1_mic_short_salt_identity_token_hmac_key": "401BF4799CB21A9277D3F643D51C5C2E5D574E53F20D5A4D6039BF8501B4B9A4", + "v1_mic_short_salt_mic_hmac_key": "77937075451137DA6E774BA77C5A25B51896BD85429245EB45FDF8D84D40ECD1", + "v1_signature_identity_token_hmac_key": "2A938DF61D8F4FC208BB76E2C1509AD85C880079F1C194287CAECE0AB03EFD25", + "v1_signature_section_aes_key": "305B71CD7CC16B254D7DB937EED3E384" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "CE71", + "expanded_salt": "52C4B782535F782334FC24FA40F001D6" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "76EEC201AB36A236EC186625", - "extended_signed_metadata_key_hmac_key": "A0F331B488ED78B4190BB62063B6A66CDA7A3503E1CBC08368E39565C307C062", - "extended_signed_section_aes_key": "BC854924304C1F14181F985F2A7875E0", - "extended_unsigned_metadata_key_hmac_key": "0A298E55442FA855F3EF35E748D52E1EABBB0FA1B3E17D24957F964F413A76B5", - "extended_unsigned_section_aes_key": "6ACFA834A2FA81A1A4A7D6DB9988078F", - "extended_unsigned_section_mic_hmac_key": "B34EFE5E312B504B811E32330C120106154D5303F431DED9FB1FC845C71CE193", - "key_seed": "FFE98778134B058DDA1C17F3B368FF6DE1C9FCE69BF5AC63C133177E707AB259", - "legacy_ldt_key": "976F3552251D50BB5E6B10A291ECA51F7E5C0C62F13035B55420530F464364C74CB41036BB8294CA2A438F946EEF622071841005B6D804412959092ACDE0A22F", - "legacy_metadata_key_hmac_key": "1278970FF627F1F077A0AF1C370317EAA0CCC33843B47DCD94C59A908069A70A", - "legacy_metadata_nonce": "23C0DB064837D54FF3883DFC" + "v0_identity_token_hkdf": { + "expanded_key": "17C531BAE241B406BB2922009FAD2294", + "v0_identity_token": "A612CAE0C2C60B0847C95556DC4A" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "F2D0", - "expanded_salt": "BF636415E72B8974D9CEA57DFBD9713C" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "F217", + "short_salt_nonce": "C7B4FA588C9333953524A7CA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "869D047A3EFED540B16C867918B5CA06", - "legacy_metadata_key": "D6C78751DF42B853DCB42F723B6D" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "DE16277E7CEC4B1FACAA17BC54474A8E", + "derived_salt_nonce": "D4FF5F07C589D8138D2FDB2A24BC0C89", + "derived_salt_third_de": "D53C34584D2EA2FCF446979A19CD7EB4", + "section_extended_salt": "F946C81199DE69612EB07197BC151E2C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "F6AF11DAE90B198388EA1D778C10CA4A", - "derived_salt_first_section_no_de": "3AEC2DD5E0D29A9EE0DE8B6C00DB2285", - "derived_salt_first_section_third_de": "29C1901D0646729360364695E47F59AA", - "section_salt": "B0955AB7ADF6FD11F1AAECB1A777A329" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "E1CD4A0A0F44E1B9EBDC99E4", - "extended_signed_metadata_key_hmac_key": "B2EFABA87A2E8BCC4ADB9CA2C94B425E824A0B9E9ADE39C000E7AFC3D4084D8C", - "extended_signed_section_aes_key": "A59CFDB9BAB8A6774B67B80F1D5EB576", - "extended_unsigned_metadata_key_hmac_key": "E975F5B3AF3C931B94F7D7ABD332BA9AF8C40F822BFBE93685714E49FA34BE81", - "extended_unsigned_section_aes_key": "B9E68CEA1E1836ADA1C2B6F72F19814E", - "extended_unsigned_section_mic_hmac_key": "9054020C39D0AC975FA1446386B282FBA102D3B13B94E06751182223E8BACD20", - "key_seed": "92CC48D1E46FD37FD8D92063C275E5601F7956B1D79EB4DA6406989177F795E6", - "legacy_ldt_key": "79873B89C6801423B759014737AD82E8774EFC2648416703942B31D831438D9C7AE96912B7CE48F10A5A81222BFD11E7BA68188FF8A68594ACCC5F3EFD183376", - "legacy_metadata_key_hmac_key": "DB7883B5FC9939D08A478BA41CBC8D205359391813FF7AA1B1CE8E5446835005", - "legacy_metadata_nonce": "CAD17CB88CBB262FA2648FAA" + "key_seed": "E145E4CDA18D67961C0286D0377554B146858D4D83365D406199928CDCAC0C89", + "v0_identity_token_hmac_key": "51094471DCCA8C3E1DE0075F09137AC7CC16A0A1C593EA16B01D21BA8BD2212A", + "v0_ldt_key": "4F2A178BCDA7D33A469327F1DD4A936F3690E9D6AC48FC69A30639833AB409641F30296928E25A32598936D1FC872A8356984FD3ACA78AAB96DE6EB2C8B15AD9", + "v0_metadata_nonce": "D8B9FC255A175733AEB21289", + "v1_metadata_nonce": "3B1A920FC87B0CD4DB45FE58", + "v1_mic_extended_salt_aes_key": "284E68D89D1634B46CFB893C4DFACE25", + "v1_mic_extended_salt_identity_token_hmac_key": "A53C4B56D2E8C308D2DC7D1A730F16059C8F352AB43350EDB6BC9FF0E8D5C8C6", + "v1_mic_extended_salt_mic_hmac_key": "4E98FDB0A10DECFF15DD50201B666FD37DECD7714DC39375807CA551EA4566B2", + "v1_mic_short_salt_aes_key": "FC0DABBB4752FEC56777FB109C1FCF70", + "v1_mic_short_salt_identity_token_hmac_key": "26B67259B23EE7FF7732B63D29FB88C6EFF6B2963742314E7EE443D062D577FE", + "v1_mic_short_salt_mic_hmac_key": "494B430E241D388B8E15EAC8B79FB531D8202019A03F171A70FEF735DEA4A839", + "v1_signature_identity_token_hmac_key": "1BB63967B26B3A8182DB6E45CE90217C48F7C7289049669114F2F60D59A4982D", + "v1_signature_section_aes_key": "C12D865CE3C3B92E3D86E11D31C4B7D0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2760", - "expanded_salt": "ACE0FB227A299B29532B691723192E4C" + "v0_adv_salt_hkdf": { + "adv_salt": "AA4B", + "expanded_salt": "055DB6E3745BDA470CE4F4C132880845" + }, + "v0_identity_token_hkdf": { + "expanded_key": "F594F0C71C5C1FE594655C37747429C4", + "v0_identity_token": "B4C958171BC3890DBE38F108DAAA" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "97AE", + "short_salt_nonce": "C9FDD6FB248C1AB3CFF1BEF9" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "CECFCF062962713BF67A2C253C34C430", - "legacy_metadata_key": "514B537E9F65528BB70C726EAB75" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "90549FA7AC9880D8007E17CDEE74FE89", + "derived_salt_nonce": "55FB1B0D6681696C15F559A6A0B817BD", + "derived_salt_third_de": "DA0D6A896BC2718BAD6B2582B3EE79C7", + "section_extended_salt": "1FCA0AE82AE6340C91647C5564742C84" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "711E72342E2DF4D9DB3E21CB79E15B1A", - "derived_salt_first_section_no_de": "4AF7B282B09493FE2AB824CE11CF5A3D", - "derived_salt_first_section_third_de": "BDECA0D713545F2C06E92ECFD90F32FA", - "section_salt": "5A7297E0F00FB0AE50DB911EA8320E32" + "key_seed_hkdf": { + "key_seed": "E4B6ED39E885C5F41D6F4D90C81C4087346E365A3E18278A7CDCA536C7229ADE", + "v0_identity_token_hmac_key": "482AFD56528CDADE549636FDABCE9587455323DF5F6BB2F9FD0C66F14F2FA4B4", + "v0_ldt_key": "0789774D2056B6A5EA53D55137B61BAE5C313FEB8BF68E3DE555EA01964B54A6F0E1E481429DE7D2BE8FEFD3C16C438EA167C6910C457F1C189251F54A01436E", + "v0_metadata_nonce": "F497EF21C812E0A4ACC14FC3", + "v1_metadata_nonce": "F1738F20E3B5B10D3E328511", + "v1_mic_extended_salt_aes_key": "1E4783B23CC12AF94BCC9642958C53D5", + "v1_mic_extended_salt_identity_token_hmac_key": "1AB2BDD7562FEF156CE157BDE824FAC8C927861B7DD1CBAA2D26DAD763A1EB90", + "v1_mic_extended_salt_mic_hmac_key": "46ECCA964CC3D606C16840222CB68074FE307938809FC97EA68C5E9EAC01E754", + "v1_mic_short_salt_aes_key": "A4EB5E86AF11AB3A4F8D70BA2D37784A", + "v1_mic_short_salt_identity_token_hmac_key": "32E95A4CFC685F4F3987F8D89C13B33C43E5F8BA1A1C76518975667B7EDD5A98", + "v1_mic_short_salt_mic_hmac_key": "80179BE73B86A9D0AFF72833F594BCF83905914646F4DB288EC11F875F1591BB", + "v1_signature_identity_token_hmac_key": "94A64B97AA4C3A474CFD819BA6FC161F2E2865B1E2B08B041CA219490F786F6A", + "v1_signature_section_aes_key": "8025F8AA3FC09DC5EF67F59C63D81FDB" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "28B7", + "expanded_salt": "6A3253C12DC5A5A9C9F2BB5FF84575A3" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "53C12B415D361B1E7CFD2BE9", - "extended_signed_metadata_key_hmac_key": "1A903300F25E61572D66E6F92E4F20526EFB141748AC018547F164847EC33029", - "extended_signed_section_aes_key": "8EDD20D6C52E46FDB3005E2F11D40E78", - "extended_unsigned_metadata_key_hmac_key": "51AC4D0DCC343FB2A8442E497D086767A0F904FD8FF0C2F5C1C3C7F462E2690D", - "extended_unsigned_section_aes_key": "DDD633E7ABBC286E409104446AACE0F7", - "extended_unsigned_section_mic_hmac_key": "57061A968056E7ED330F1C8F65242B18335B0203B3AE5F863F861FBA07155CFE", - "key_seed": "9E095A9E979E0556C03FE1276821A0905A530027A4E48B445FF150DA40A47BC5", - "legacy_ldt_key": "74EDD1187CF248366FADC5DD69BB431EDB9FB39621221F62A67FED5CB3D0129EE8B5526BEEC86BC1CA0193239184A23D70D901B12F89079E1560A25AC839F6FE", - "legacy_metadata_key_hmac_key": "5B34A6319FD27843706A8E1A7A1E779200E3D9BE8DA1246CC5E32D88DE816486", - "legacy_metadata_nonce": "F23109B82D2099F6F94B4C88" + "v0_identity_token_hkdf": { + "expanded_key": "942E2707FA20651603FB9BCD1483D57E", + "v0_identity_token": "79F541A8D757F44FB52031C6EF7E" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "FE58", - "expanded_salt": "9C7EA9924564F03D6340019D4BCBBA47" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "1299", + "short_salt_nonce": "911ACEFB50B97795D2A96537" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "439B31109FE781639C510638CD037A12", - "legacy_metadata_key": "1F22EFEAA64F55866D64968A732A" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "5BAA0ED9252F176221DE2D9E287C731A", + "derived_salt_nonce": "220F098C6ADCF4E24B6762E4CA4DC7A6", + "derived_salt_third_de": "FDB6D13DB24556E6A1E926CA5080B20E", + "section_extended_salt": "C10AF6288A750A0C71B7FBB3057BBAA2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "F1CA484DCFEEEAF8652F00199C50A97F", - "derived_salt_first_section_no_de": "9F52A5DAA201CD3307BC80F9A3FF5A64", - "derived_salt_first_section_third_de": "BCC55DC7AD531D04D24F88CD03FC9947", - "section_salt": "96E68F69CE0AF1CA5947D950AC03167C" + "key_seed_hkdf": { + "key_seed": "F93748CF451F971291D31EB2D25948BF10687D3F3955D5A6EB6BAB4510E003E8", + "v0_identity_token_hmac_key": "BA87E890F118FF9516B6054C89212CBA85D3413E236865E71CC939AF0A48D26B", + "v0_ldt_key": "7D6E7092EF91CE57885E3F7250DC889064C9B657A8BEECC800EE8DA3A5E508D22CDBF4C8164CAD7EF9067CE25B1A51693998A3FCC4974B80AA26D0A08FC1ECEA", + "v0_metadata_nonce": "CBE2FDBF7E222F39257C4697", + "v1_metadata_nonce": "37181E07F73F64E6D39549D9", + "v1_mic_extended_salt_aes_key": "442BB1C9309855CC0C81B319AC4942BE", + "v1_mic_extended_salt_identity_token_hmac_key": "905919A49E80A3F5DC2471AC9CEB9588AE9266DBDF346F9FEB05980466A24A48", + "v1_mic_extended_salt_mic_hmac_key": "1BE4DF51E2A244F17793D9C3D1EE2DDC9FC992BFBE378C828DBD1D3121F4D9EC", + "v1_mic_short_salt_aes_key": "FDB274DA8F75B1DA00CEAAD2BDD6BD06", + "v1_mic_short_salt_identity_token_hmac_key": "750DFF2B2046595041B400945833A3434B39D98C23975040C6192F66959E40B7", + "v1_mic_short_salt_mic_hmac_key": "19F78A8FE548117BA40809FD8F602F2FB9A57F6EFE01756A93A81A6BBEA0BEF6", + "v1_signature_identity_token_hmac_key": "48FAF93A1F41C85646B0204CCEA6C145E7CEB69BA38F3FCF3979E4F9A34747BC", + "v1_signature_section_aes_key": "34324281067F3278984109B434594C84" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "9021", + "expanded_salt": "024D17ED3BC1DD62FFC281DBA42F6CE9" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "790DA0B3358A34B85EAC7667", - "extended_signed_metadata_key_hmac_key": "8CA9AA70936AFBCBABF150D6E5B27AB91974D4B039CCE5C1F3AD7CD09B124F08", - "extended_signed_section_aes_key": "9B148D55787368596D67A8536F89214E", - "extended_unsigned_metadata_key_hmac_key": "2497B036129D2F25F43E6838495CA54DA3E39DFBD80906C945F1C536CA8B54F3", - "extended_unsigned_section_aes_key": "680EB9CE125DA2B614C1768023E69C8D", - "extended_unsigned_section_mic_hmac_key": "4FDA73846885210F5E42B57D32C559C5C176B4FC17A5DE755E9832F7473A6615", - "key_seed": "1C21EF77FDCFE2F77ADC1687CCB48A85C71A6D53E8BBF9C445F9A81E44C96010", - "legacy_ldt_key": "65D36DD12CFA1D5985EBD4547CEE55D85A439A6879A390A114E8265B52DDC19071E346DE0F8AF67D8D91B506399043DE945F3B61F0698D58E80543BCD6FB57AF", - "legacy_metadata_key_hmac_key": "7D96F6A20DDE772C03F269C6B5D1851A569C300D5B0277B7AAEF6EB9C71C884A", - "legacy_metadata_nonce": "3E4300FD8F982F491BD335EC" + "v0_identity_token_hkdf": { + "expanded_key": "2CA6D8809D9CC54B426A5D631F5DD5D2", + "v0_identity_token": "C17929AECBB954C19B7D9FFAB41E" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "9CC4", - "expanded_salt": "61B568A967985A5611EF9256E29E9894" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "F2BD", + "short_salt_nonce": "760FE743C18D50BC5915DEAA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D477CF6201CC1CADBA21370D16760F8F", - "legacy_metadata_key": "50841355894155E171A91BD507A7" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "66980E111A8AA401E3B96E7E0EA44FF5", + "derived_salt_nonce": "51074A20BC98469D5E302D454A661CF1", + "derived_salt_third_de": "0A7723EEBC848E10D5573084A5AA9326", + "section_extended_salt": "3CDABDF68AAB76BA4AD395BEB668D405" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "DCA35224242C81D062E2D7806C58D0B2", - "derived_salt_first_section_no_de": "54EF44DB16594004E554658EFA470231", - "derived_salt_first_section_third_de": "001814C42510FCD65262A3B4CC145933", - "section_salt": "B601766283CBAE3A4CE5C7DFF2A0DA74" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "A15525217C62F032E6D54151", - "extended_signed_metadata_key_hmac_key": "298E19377343EA2CA328F5BFA39DC8517F1C426BDA2171E0A09208C39BA50145", - "extended_signed_section_aes_key": "2167A0F9007EB1A8EFED8341491C5B68", - "extended_unsigned_metadata_key_hmac_key": "2219E955FC16E04FEF31B79E0C620133CC4BFE2CD2CB6FDFB756DD88FDBC0799", - "extended_unsigned_section_aes_key": "1F7AE997F2B6D9AE904158DDF91C7A62", - "extended_unsigned_section_mic_hmac_key": "4D3627566109F030079FC771DED6D567F556A1FB703A89C51FB76C2B59FC5443", - "key_seed": "121462ED1B16BC8682D880878916CDB81CD7E7556FEEBA1FE22210D2949F0931", - "legacy_ldt_key": "0EF6436C70F2797E08DCAE6D368C1C3EE7B8578572EA873C8B7C185D8CD1616FB0F33F4632618E4A60B9B6F9FBFD7D34655A50C444995C7059C93DD28AF58176", - "legacy_metadata_key_hmac_key": "184A3999BCF8CC12D37D4013D7822C64A11CE426267A0271C1ED53E7E8DB1000", - "legacy_metadata_nonce": "78C1769887FDE04453C81658" + "key_seed": "6BE4BD51107BCB90669934994487DFFD384C30A08A130DCF058DFA9CAE77D7B2", + "v0_identity_token_hmac_key": "36DB5DF09F5706F43F19A6A6A6DB9EFACE7C0945BE5CCD6FD9B41E514D3ADF6E", + "v0_ldt_key": "6B1D1F8670DF12FAE850EFB556A52E80AF256644C657442BFF5B6A8535C0532CA642511E2EF35C9BBF583F051594656F4D9EA1C8639710F51033600488B3C5D7", + "v0_metadata_nonce": "E64647D6D6428CA9356F587B", + "v1_metadata_nonce": "9446C5C7C84F3592D1BBDB63", + "v1_mic_extended_salt_aes_key": "A466870E3E012FD1D47AD9AD1A70BB00", + "v1_mic_extended_salt_identity_token_hmac_key": "303A9851761A21D1B8F8428FA5EEFE4311C10CE0BB62E0C846D336C829B626B1", + "v1_mic_extended_salt_mic_hmac_key": "4EFE91D05602871EF06FEE7A9B2DB2ABF8FDA8093467E2B7E5437176D24885AF", + "v1_mic_short_salt_aes_key": "6465CF64ACF1F01D2D5D9D1441B2E4B9", + "v1_mic_short_salt_identity_token_hmac_key": "F5129A6C3923C228366A93A12BA8287B1C2CDA1A6CFDEC305C7FB224D92EDE7B", + "v1_mic_short_salt_mic_hmac_key": "30876F2D82145F3754EBD7CAF699A3BA64458F0846C9E6047485B5C209F65C1F", + "v1_signature_identity_token_hmac_key": "AD8B825C5A010150B5F2AF5A3FF073A3EE199654BBBB073E4D902FE4D0AC5A48", + "v1_signature_section_aes_key": "611B58E120CDE3E26F834932C36566DD" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "296A", - "expanded_salt": "F44EA8B30FD9F999BC7E31C8130892C3" + "v0_adv_salt_hkdf": { + "adv_salt": "3CA1", + "expanded_salt": "8DDD8654D5EF2D402D1BD89677B3B2F7" + }, + "v0_identity_token_hkdf": { + "expanded_key": "33A6954AA51AC176229053887D832EB7", + "v0_identity_token": "45694EE6AB26F4B895349E87F727" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "D982", + "short_salt_nonce": "72163DAF1F557C67B89BA7B0" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "4299BCBB2412A71215EDFBFE1F8176E7", - "legacy_metadata_key": "07C4A089310EACCA1B3BA2D4EA94" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "84D7B207BC3AC861E317C4427A2F3301", + "derived_salt_nonce": "498C9B6F78B4E5F68FCBDFA5FAD87C0B", + "derived_salt_third_de": "363C6DADFC2F7B20DB94885929867F1F", + "section_extended_salt": "9435272D1BBC6EA6FB74B94D6AEB5AF9" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "F3CAEB25DC97A317A38C99E7F1438E1F", - "derived_salt_first_section_no_de": "EC4686E3C2F9A5AF8934C8EADAFAEB6D", - "derived_salt_first_section_third_de": "921DBFBA6B75D60A97443F20A6AE5779", - "section_salt": "F3A5EA6D8CC24F111F84B17EA038A2FC" + "key_seed_hkdf": { + "key_seed": "9A5DF1DDC5B966E46275F11196A5FD20AC8C785438892A20AF9CC19D1F024234", + "v0_identity_token_hmac_key": "0CC4D92F3CB8D258086F2FFAE0D3C00CA5D091666B506967365A20BAFDC8075D", + "v0_ldt_key": "B002ED5E3E3A89138132968C513DCCCCE3505AC181845BF28BED504BCAEAD1B9992A869C9FFE5869AD40AD9088B6B3B3C0C84152A15A65861B9AA5E1C15B0A48", + "v0_metadata_nonce": "A71E83B5E9FAE0461B560352", + "v1_metadata_nonce": "D68843EB7043254F1F786CB9", + "v1_mic_extended_salt_aes_key": "4A32421BC387873521C5DAC5DD9BB2EC", + "v1_mic_extended_salt_identity_token_hmac_key": "1043596317963E0FA7B386319B95A23EC6E2B8BDFC510F98C2D55472FD479CA5", + "v1_mic_extended_salt_mic_hmac_key": "D619E81CC454D9988BAEE3126A279B2E06E91555B79E736D3A148BC5562B7640", + "v1_mic_short_salt_aes_key": "7F710EBA3B7926655AB09CBE0B907506", + "v1_mic_short_salt_identity_token_hmac_key": "CD64A6D97487DFA1AB1893D5E00117807F598A2AE118654996BC1E3DE8F8B61A", + "v1_mic_short_salt_mic_hmac_key": "3C5F8ED49E7B095E21F3DFC00E92C34A6291E6E445FB181EB5612FB45389BC9B", + "v1_signature_identity_token_hmac_key": "FD265D72D87FBB7503D2B532DF0F03F916FB41D82758D1A6BD1E71AF1C3C99E8", + "v1_signature_section_aes_key": "C715D287A1C5131332DE38C844EC32D9" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "38BA", + "expanded_salt": "BE558E77E1C1CB6D3B412593604D212E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "944F676AE58D1738571A6988", - "extended_signed_metadata_key_hmac_key": "D5642BD297591472FEDD16557F86D9FC98701FC19BB83E24A87EE5D31314CCF7", - "extended_signed_section_aes_key": "B2FE576CBF190EFF36B7DDF428D08806", - "extended_unsigned_metadata_key_hmac_key": "80E4277B7C98DE76783580F99D7AFFBD0C939069E129FCD2A451DE2A4DFB347C", - "extended_unsigned_section_aes_key": "84AF72363AC42837703E0233DA58AF15", - "extended_unsigned_section_mic_hmac_key": "309CEADE18269614513CC150680E07E79A395BFD00966021D074AA51D5DBB0B3", - "key_seed": "174C6D54B1B0CC84774E8FB9339AC57933CFEC2D78A57F66268A2ED648C79D54", - "legacy_ldt_key": "FEFDC3138EC8C0F7CC34C171A43E9AEEBB4A0FE5EAADC607A9D6600D8B9B54D207A2BC90D0B38DD989EB57AEE3A21F11DFA1C22F8DEEFCBB84F14DE16706CB5E", - "legacy_metadata_key_hmac_key": "181967500164E896A23C22E206E00208E0A82CBF97B839DA87F9C3EC5759F1EB", - "legacy_metadata_nonce": "0688E75E1B921F995491EB07" + "v0_identity_token_hkdf": { + "expanded_key": "3249439E945688E53E2D09CECF669801", + "v0_identity_token": "262E2E4C531A2756323900C354C5" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "BEB5", - "expanded_salt": "C401AFC676735287424E9F7F0DF237B2" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "1C05", + "short_salt_nonce": "F93616C2AEC28E78FF0B5D0C" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "8AB09C04AC42D4F4E123FC884885C595", - "legacy_metadata_key": "191530A2A7F75BBDFD7777601AE1" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "8F505CBB29A4CC1CD037D1864D15141C", + "derived_salt_nonce": "03A12AB647E4834E3E507F1F6EF20F1A", + "derived_salt_third_de": "654F8A7CD26F23E82163007DD25029B9", + "section_extended_salt": "AD43FF79BFF583BED9ECAA14CDDA4B4A" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "99D022786E9CC9AB870AC2FF57DA80EB", - "derived_salt_first_section_no_de": "01E17F91C55F51BD79A72463BC8493F8", - "derived_salt_first_section_third_de": "AE2DCB3E34AB81BF22F460D7546376F0", - "section_salt": "3E1F652AE28F8335D7B15864E9F7CCF5" + "key_seed_hkdf": { + "key_seed": "FD4AA335CD6FE01E9BDD45FE11B306293BBECB92F1D2CAD39CBD1AF43ABCDA60", + "v0_identity_token_hmac_key": "406B8E5E105F55217B0687BA83B5DDA39C541DA4D53015D7E9CB83DD8A6A307F", + "v0_ldt_key": "F5F2E863B32E3B216EB59D37C1CAF3761D6BBE6A089ADE286390690C0C1DA5AD5CB3B647D9CD210ED63267C98C2893D17988B8A1D03845AE170E737CC20D0185", + "v0_metadata_nonce": "64FB1137553FADBA3814DD0D", + "v1_metadata_nonce": "1DA66804A1577592B5D88534", + "v1_mic_extended_salt_aes_key": "204CE842E93EDBEA97BBF662EF60C006", + "v1_mic_extended_salt_identity_token_hmac_key": "FE3DE77C3C83956B52F85C4A6284B97BC69E2D238A185F2AC7AD7E3A042D7883", + "v1_mic_extended_salt_mic_hmac_key": "208EA31DA316646310DAFE2A4036E5A1556E80020D8EE582DCD9CB6DC475B625", + "v1_mic_short_salt_aes_key": "0B308555FC29F102CF5AF79AA5C5D85C", + "v1_mic_short_salt_identity_token_hmac_key": "5F89875055E105BD96055508E440A6A6B44AC0F867D642FF95EBF249D2A28BD8", + "v1_mic_short_salt_mic_hmac_key": "54F0E228A0E4761F1694BC2717794E2C79BC9CCA99A0B368A370A83750468223", + "v1_signature_identity_token_hmac_key": "5838D84FFD60A23225B059EFE52D7FFE71CDFDB599826D8BBCF2E254FA5B72A7", + "v1_signature_section_aes_key": "0BA6F0BE32E0E8AF932B27A38BFF678C" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "1D76", + "expanded_salt": "03BD30CAD853D018A141F8DEF1F37112" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "F3ABE0F91D65A95957CF2AD7", - "extended_signed_metadata_key_hmac_key": "0F4E56038ABF9ACAA73EC95395B337124A89ACC20399E1DBAB7F8F73182BC107", - "extended_signed_section_aes_key": "13B7FEAF3CD5ABF9905CDA55AFDDEFF4", - "extended_unsigned_metadata_key_hmac_key": "B42A14360C1128B0B4AA1D99E89B32F4D13D2C8A191EC5E58DB841EDDC4ABF76", - "extended_unsigned_section_aes_key": "3AE1FBA492CE6D8854923EEAC2AB8A17", - "extended_unsigned_section_mic_hmac_key": "9FF77BD8BF275AB41652950CE40976102A641CE5CBCF346A9E755281FC0259B3", - "key_seed": "9864ECFD656E7B608A63883FBEC4F62E8E6F7A3590114C39E036AEC87BECBE41", - "legacy_ldt_key": "8FC7B079C4225368931B03C4814EAB6DC02175EF1873B1A224CFD39B9CD99814417A884A2FDB9D324747F55A9BF7758B22C2C3113D06ADC373B0A47E925FADF3", - "legacy_metadata_key_hmac_key": "493B6E99413B5E07771053F536EEB8DBF169B4DE6E78EE341E1627C5055200B9", - "legacy_metadata_nonce": "B4245B6A65DA3B698B64B9B1" + "v0_identity_token_hkdf": { + "expanded_key": "9355E90CA1E607F24358C2898E658346", + "v0_identity_token": "636CFD6764F2586AAD40ADD23774" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "8C5F", - "expanded_salt": "1E634D3633DB16B5698B53B1FAC7318A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "DAC9", + "short_salt_nonce": "ACF0BFA6CF9267C79BF71814" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "ABACBBEA70871DA67332DAD622F9877E", - "legacy_metadata_key": "711C81AF55689C9F41F26EC0B3D9" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "588B14F40986244A6E6E11B59DBE6004", + "derived_salt_nonce": "8F4780C654ACC3FDC454F59459EE4806", + "derived_salt_third_de": "433266A654D8821576954A6122E18ED5", + "section_extended_salt": "5D5394D0EF11A3C4C83A1B3F4DD1340D" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D42F8611248F16803F100880FD2C40A8", - "derived_salt_first_section_no_de": "0AFD085C634D64812B22120E6EA087A2", - "derived_salt_first_section_third_de": "0530E299A7CECDA05EF000FCBD461AE6", - "section_salt": "1025402C2B74145C70E2CA2E518A83C4" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "37CAFFB8E8BC64931F3190F3", - "extended_signed_metadata_key_hmac_key": "15D89B2AEEBF854A0BE65C186885E4AAAB903E312CF27B67F8881FACB082B7D6", - "extended_signed_section_aes_key": "640271AF293235DD4592A0FD12EDCDBB", - "extended_unsigned_metadata_key_hmac_key": "3E5D5FBA4B63F41DD8B5F42C1A285DA8C0AACD5AE96891BF9BE94BA7F2A3422E", - "extended_unsigned_section_aes_key": "573C4B8052EF1CB1BFCE2EE02A21FDDB", - "extended_unsigned_section_mic_hmac_key": "269360FAD76012F1BFB9B46E48CCB4A4484C959B46AAF666E7E99BB571D02DBF", - "key_seed": "AED5B53B0E0A4A8E7A00B1DFCC03428D99E7B07CC6B90A2A226DAC3C51C53300", - "legacy_ldt_key": "80B93319EEC4CB0E43E07CE1DCC54AFA5143E3E0688297837BE19921550E3903AC441802CF7816C959C8BB5B5F650C294379767E8A13821F0BD4CD0164748355", - "legacy_metadata_key_hmac_key": "AD90B2CF579CA71E41CE8EED3E8D2EDBE74BC6B3E090C298B3027E2071E1D707", - "legacy_metadata_nonce": "28C25CA1937E414689922A89" + "key_seed": "8385E64B2E3EF21FAA2E01F9A7E3681B17C7DBE0498B3A9DB7CB25E9D62EB6ED", + "v0_identity_token_hmac_key": "AB4C142CE9F73CAB064D3533B1980B1B4B88B98AED58171986D28966A127F45E", + "v0_ldt_key": "8978107F05DBC75203A1D8B09C2B3C3508207EAB51AB43312FA2D6AA912DA366F050FB8EE7A1AEC265D08F47EE1C299B4B8E526A62EE1CD529294A0F9166B135", + "v0_metadata_nonce": "48551A9BF3E51223B4FA83A2", + "v1_metadata_nonce": "DEEED21180C62518A729ECFA", + "v1_mic_extended_salt_aes_key": "CDD92FF2299C64640DD4DDE767B8447C", + "v1_mic_extended_salt_identity_token_hmac_key": "475944CC40A29812841D147B2F1B8E6FA3B1960083DB50C373F1D032C05C32D7", + "v1_mic_extended_salt_mic_hmac_key": "2ED15F9F067294394BA5F7EB2F554553CB932E33A8C10E6AC3434FF1A7F8DD2F", + "v1_mic_short_salt_aes_key": "CA73989C086C73B114AC605A79A0F8F2", + "v1_mic_short_salt_identity_token_hmac_key": "63269C17F98AA0029E06EA1B749D8DB6C28ED916906DD28F1A3A8C94E31DACF9", + "v1_mic_short_salt_mic_hmac_key": "AD1C3A30332FA34408CA62A9C6B9A5263932EEE57829C1195DC74127B1C88671", + "v1_signature_identity_token_hmac_key": "99B0BDB55C04EAEBA66E40815CA346C596D848044A16F8A8CD1E8F22E4B11F97", + "v1_signature_section_aes_key": "5F2B10AD3A8C1803B080A1F99239B66C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5CD7", - "expanded_salt": "3479EE965DA3C29D12C79B83F87DE36A" + "v0_adv_salt_hkdf": { + "adv_salt": "D451", + "expanded_salt": "B73C8091A1D606893FFCE4BA8DD96D80" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "EBB365F56DD11C290CF18ABAAA208F68", - "legacy_metadata_key": "798BB2405B1E4C58708885C8C64C" + "v0_identity_token_hkdf": { + "expanded_key": "3A1461B8D59E8F9AAC4DE97877E97A56", + "v0_identity_token": "2377F0BE5EACC04FA6679BFD6DC0" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "7A24", + "short_salt_nonce": "D13C30E6D309831E754A8B5D" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "22A24B673F12E4066B1058549ACB431A", + "derived_salt_nonce": "EEF802FFAEBD8AF451F5275934E2F8ED", + "derived_salt_third_de": "136F8970074C895F2195791B5636A000", + "section_extended_salt": "18B6A2DB75BA6F6C2CF40473B7673D48" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "E06D761A8CA571BF0B0F44BECE8D84E5", - "derived_salt_first_section_no_de": "F4FA7DA6B4BEB32FB8D61AD5529221DB", - "derived_salt_first_section_third_de": "C8B3BAE8D808A3E4CACFDF99B9006801", - "section_salt": "44829BD9245724BB422CDF85FE06575A" + "key_seed_hkdf": { + "key_seed": "B5F5FD3809B1E2287363B843688B8F263B36F22A818CE6D653AD2E202D4C2029", + "v0_identity_token_hmac_key": "8FE854C9FCB565B6E74C28EE13B9740B3F0A76F1BEB869A6EBBB7DE4999F69D2", + "v0_ldt_key": "F3B0B3A99C8AE9E6C111C2378C15396404E32B7278E5B3B5514251EAB2FECE631528F1EFE06CFFCD192C2D3483D00760C4D5F3809D32B29ECF4E1A9D9422F6AD", + "v0_metadata_nonce": "820F6CC121CECB5D770CBE5D", + "v1_metadata_nonce": "371063E1C363EE10DD07C754", + "v1_mic_extended_salt_aes_key": "78C14BE8C5AC8D740024768A2B59F13D", + "v1_mic_extended_salt_identity_token_hmac_key": "B0CD0B70103C233E66D37E621EE40A04873D917A70D2E647FBA106399AFF720A", + "v1_mic_extended_salt_mic_hmac_key": "1FDF6A45C585A0F1B30CB767AD84410A2B95628635124F63C05F092918768D6E", + "v1_mic_short_salt_aes_key": "2C30551B0B248E7AA0C567A9F1F588A2", + "v1_mic_short_salt_identity_token_hmac_key": "CE516307270755B243FF272BB9A38EDA69BA0E04771E1675B5CFF1218637CC36", + "v1_mic_short_salt_mic_hmac_key": "BA808DDB430868DEF3BAA9FA53D9FF19BDA2559876360F87DEC0B4D04E6B482B", + "v1_signature_identity_token_hmac_key": "B90E66D1CC33DB3DEED3F867C42569514764A2E4E26D6E65A5009D3C39EF0BB0", + "v1_signature_section_aes_key": "5E4075E092E92885446D7D362B52D788" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "3E8E5771EC037DFE9655CF21", - "extended_signed_metadata_key_hmac_key": "FB1E172D8BDC30C0686494050F0545AA14AC4CEB4B80178D1A60BA91F52E4220", - "extended_signed_section_aes_key": "CCCCAB2218464982259AC1F9E1C883C9", - "extended_unsigned_metadata_key_hmac_key": "A165FBA7AE751FB806EB71B517C107108ADE8AD83CAF2270CCBB500A16D6E8B8", - "extended_unsigned_section_aes_key": "939BC65E829C365A53FA76DEC5CCAF72", - "extended_unsigned_section_mic_hmac_key": "F517D42A409DECE9A73326D2D83073F5354D5FA6E18E361C8F5C322DF0DE2074", - "key_seed": "AFBF0717AAE34C12160C6699E875BC497324201A00F28BB689E72FF81EA02083", - "legacy_ldt_key": "64701C13AAFD18BD719961E5168794D660F2B303265D8164B3F42DA11DC1689AF643525BD5674FD39E4EDA98217D04C0F72188D4290C1820C3E7DD999E5C26A2", - "legacy_metadata_key_hmac_key": "3228A4757D856906247B16A2E70ACBA3E2B3A556B48C3F34188605EF76C36EEC", - "legacy_metadata_nonce": "5E989D42F47971FBB6D02CA2" + "v0_adv_salt_hkdf": { + "adv_salt": "E077", + "expanded_salt": "A6B67A4794E7CE03C296D02ABC551D86" + }, + "v0_identity_token_hkdf": { + "expanded_key": "108E348B0D134F66511A75D575F3A1D7", + "v0_identity_token": "E79958E8FF15C1F5B7857F2BFD5D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "B7BF", - "expanded_salt": "B08300567B79FF302A5C7E88AA9FD54B" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "735B", + "short_salt_nonce": "808310562C7E7A9F797FE241" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "D98863233D54488599DDB89774AEE330", - "legacy_metadata_key": "0077F1879D872A287071D462AF20" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "D063EED8AE6DA992FACCD9BEAEFF9D60", + "derived_salt_nonce": "49FB1F75B6A395722D25D76BF3B5CA35", + "derived_salt_third_de": "86575CCD43CFD910F9103697669DFE08", + "section_extended_salt": "AB63F5E51D36B4C5CC9C302876BB2C37" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "CAB00A6159E6DE851D7E64435197DBFA", - "derived_salt_first_section_no_de": "9D33AA17D4672886D95B8040F714E99A", - "derived_salt_first_section_third_de": "F000BFD919B6C082652650B4A5C5E1A1", - "section_salt": "11D3A895308F443C74723FE45C9AD464" + "key_seed_hkdf": { + "key_seed": "11BC6308D6F1B051F733F9ADD041E90BEE2B19725633988B416F1EEED3C1EA8E", + "v0_identity_token_hmac_key": "7DFBD6E8C3D38FFA86D57F9984A91D79F0092F15DDB133C99A35C23C1EB7FF6E", + "v0_ldt_key": "15B76645533D06841647A3079A81C60F862CDBF49BD259DB3AAEFC7909B8CC14E44E63E04410434E541C99A00017A1D91A1D48F3960CD19460B17FF720252727", + "v0_metadata_nonce": "134D3F0E1599C745191BB287", + "v1_metadata_nonce": "7E2895642ECB18F17843FFF5", + "v1_mic_extended_salt_aes_key": "E75A52D878873874712BF3D7BB5419E7", + "v1_mic_extended_salt_identity_token_hmac_key": "A61F230BA907B4C754FBB42BCEADAA92221444FC88FCCB9B1ADF04AF88035D27", + "v1_mic_extended_salt_mic_hmac_key": "57EEBAEC158DD1DC90F3B1D8884CACB5FA32322E4E7C4EE21AA0EB175232498E", + "v1_mic_short_salt_aes_key": "CB4C2ECD3F7058A3FF10FBA90939B090", + "v1_mic_short_salt_identity_token_hmac_key": "A09E42551B882B1E6FDC075FB2A379332C66F91C3FD2DE496E16AC3C57FB2F88", + "v1_mic_short_salt_mic_hmac_key": "4746E3679A6D724E53E049DB091AF90619DAB91369DBD18204E346B2BD69FD6E", + "v1_signature_identity_token_hmac_key": "6944BE9FD3E6F9FE05843758B8185862A8112941E10615767A7E41A76E6B1136", + "v1_signature_section_aes_key": "4A4A874A9EA2E43F5A9F76E7B2C20283" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "9594966607D85F389214AE63", - "extended_signed_metadata_key_hmac_key": "FA1A0A53C819972F4E4F9DC3557D7E48EF74FD16FD1B4E6E343EC2DB2CAC2812", - "extended_signed_section_aes_key": "03570780D11AF5A85038B03FF4DD0700", - "extended_unsigned_metadata_key_hmac_key": "7379F3362DF6C3204A4B334B8AE60369493FF4E5296C5A7AF2485881940F6170", - "extended_unsigned_section_aes_key": "2DF64D6C5F0843468AA52DFAA6A587CD", - "extended_unsigned_section_mic_hmac_key": "6259F5119F8B9D77E2DEB23DC41A54DDE67742AD520F225E83E67E98C44DE6A0", - "key_seed": "5EA0EF5C2E1E60B1741DAD421FC11EE78391D9598D143B5DAC4FB07091847EA3", - "legacy_ldt_key": "A2D8CD41763E0C7F5A24C05FEA4BBF9C05B50338FAD3B877F69A81768FA01BB0CC9704C1A8DCA929025CCC8F6E80507FD74D140BC8D56EFE9E201F2C34077DDB", - "legacy_metadata_key_hmac_key": "B5CCC3B2437D3D659C4CDFDF7B0EF920A5ECABFBF75DC6C36CE47E946F35CB9E", - "legacy_metadata_nonce": "745E3B9CDE832DE4EE67847F" + "v0_adv_salt_hkdf": { + "adv_salt": "4B85", + "expanded_salt": "7E6520C25AD0706CF1B053B159BAB155" + }, + "v0_identity_token_hkdf": { + "expanded_key": "356B301E5F432F5AC986BD0E0803812D", + "v0_identity_token": "05038424718B35F01CEDDA0AE654" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "81EB", - "expanded_salt": "400E2A436293377A368189866BF5A615" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "E1E7", + "short_salt_nonce": "224F4CDE51A4C3379B542B1E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "C0B5A3D9B7E8EB4D8A68F6AA158D0C90", - "legacy_metadata_key": "8E9165673AEFCC49B33E4535E0AF" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "4CED096908CA26C394EC58083D07668B", + "derived_salt_nonce": "0676D12F882BBE0106CA0BB3138F0BB9", + "derived_salt_third_de": "5A1A19BD6F8C55822C6B51538206B166", + "section_extended_salt": "59D1E9BDA1B9BBC808157A8EFA1D6BC2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "0FCF0C13F89FFAFF9CF2EBB9C74238B2", - "derived_salt_first_section_no_de": "D1375663E1B57A43DD17E6FFAFC17279", - "derived_salt_first_section_third_de": "2EFF6AC282F726CA937B8B9AEED2B9FA", - "section_salt": "76B2FF4BF7A1754AA61E2FDD6C88FC30" + "key_seed_hkdf": { + "key_seed": "32E24295D7ED86DD0F048F5AFB62251E5BBA5FF34E2C191F8E89277E93DB4200", + "v0_identity_token_hmac_key": "4056DFA3904F3DB84F85315807A1ED8AC4B03A0FB300BB64C244FD377F8B8350", + "v0_ldt_key": "D4F8368C22558EE72891F005C5DD4B62C2AE562147C7E7A6B1041E2B8387160CE1DDACFFC1EE0725DBACACF79A6C1AB7F16DD15DCAC3EE96DA0EF70C03CFB261", + "v0_metadata_nonce": "5BD37F029FDDCF34D94D9723", + "v1_metadata_nonce": "9AEA4508424F0408F12D3F83", + "v1_mic_extended_salt_aes_key": "4FA46CB81F16D1973C228D94A26B316F", + "v1_mic_extended_salt_identity_token_hmac_key": "A0D1CED918D2A3D702E2D1E81211247FABC8E74E28614FF12B86DA38FE49804E", + "v1_mic_extended_salt_mic_hmac_key": "6C6BB48C73B078F00191FCD9E5A6F9E51540963C3B11B242DBC6B8C4EF5DC396", + "v1_mic_short_salt_aes_key": "A75EB826BBE44DA0B11FB0E93B06F661", + "v1_mic_short_salt_identity_token_hmac_key": "3848F69057BE12FF81A53754431C32DFAE36155AB7069ADB0C59A441F3459C68", + "v1_mic_short_salt_mic_hmac_key": "96EF80B80CB868F76C623029EBBC45793B78D584F43D955930C74EACF1256885", + "v1_signature_identity_token_hmac_key": "1FC9D1ECDBC54491BE8F60F7663EF74B551FC5734620463D55E6A561A2AF6945", + "v1_signature_section_aes_key": "72EEC64698FBD42D3A53F84EFB88EC3A" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "B65D", + "expanded_salt": "ED9F26FC67AD4BEDFCA31BE3DD4E2173" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "5706AFC8EE2B6341CC4D3B05", - "extended_signed_metadata_key_hmac_key": "D790D59CCEEEA5A0C804429344D35C3AC9A515A9CFF7E10043125388CF5D326C", - "extended_signed_section_aes_key": "E23DF3CEBC1F83A569DDC05DE27DCA19", - "extended_unsigned_metadata_key_hmac_key": "A396B34DBF66E482B53D2B79DABD00F098E1E5240D45C3805F2386A1237B06ED", - "extended_unsigned_section_aes_key": "03D99FA28322A9506C3CB7B9F51F4542", - "extended_unsigned_section_mic_hmac_key": "E495765950E61B023CB6E2686ED4DC4189CA56F915CB3AF877B15ADE845EF31A", - "key_seed": "206C196A03EB7DE2525B6C27E478552CD3B1904D4D89D3785D51C02B8F1D9B36", - "legacy_ldt_key": "71534CC9368B8B599431DDAE5F62200DDFBDF8009248436F92636CF214F43E85CE80EC8703B78FC26503F6DD3634526B7301D8DDF45339A3B63C64838A09734A", - "legacy_metadata_key_hmac_key": "3158EF75327E4F117A5ABAB3EF29954CF76B7249C74DC50CB8D1EE4027F70CD2", - "legacy_metadata_nonce": "704A450B927CC83483CB5210" + "v0_identity_token_hkdf": { + "expanded_key": "F432735228DB941C89598E37EC4ECF1A", + "v0_identity_token": "70AB53CC636AF05080929153F78F" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "4E36", - "expanded_salt": "D96E799C1F673C3AB5621DE38FB7D9FE" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3309", + "short_salt_nonce": "3701F88A64084BBC60178848" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "DC4C0824F5965E110BE7C9036B6043D2", - "legacy_metadata_key": "D2DE6C51A1B2F0CC740A0433BA0C" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "7A718CFDEDF904C7A72BD13FD5DFDF47", + "derived_salt_nonce": "53C9C943AFE5BE0EF3EEE3859B536A4B", + "derived_salt_third_de": "42726C30FDF62DBDA0074E6FAE969CEA", + "section_extended_salt": "45E80FFC36670147E8D2CFBA526EFD42" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D735F933C91F70E6703FA277DD9D6B07", - "derived_salt_first_section_no_de": "A1216FDE48D4E7CF716EBA6304B0E002", - "derived_salt_first_section_third_de": "6C6F84F7B0ADB3DC95733154462DC464", - "section_salt": "EE077330D38FA4E741EEB2A423C44E16" + "key_seed_hkdf": { + "key_seed": "229032F519800B9A2527068EDE2BB34852628ADCAAC3F20CD72E93B01D4AD9C3", + "v0_identity_token_hmac_key": "0D3D137BE4B1478340EF1FDB8FD01B917B72FD783151505E1A7D8782F9A53342", + "v0_ldt_key": "AA6E607B24892A16693EEB60F05AA306B2513F8D65E8A43BE6B9C135C2E6E8EFDDE759A13EBE077CC2D84785514D6DC55FD8D3BE9D075003C7BE9D7299ED9F8C", + "v0_metadata_nonce": "026E8C93F32AF7A8BEC2E014", + "v1_metadata_nonce": "E3A33A83F8DDF01A20423453", + "v1_mic_extended_salt_aes_key": "E4F8998F78966160243FFC98073E27EE", + "v1_mic_extended_salt_identity_token_hmac_key": "47BC89710BF706CED760412959675300B62B997402FA5BA1969251B22903874A", + "v1_mic_extended_salt_mic_hmac_key": "A0C758A7EF5B92B5CB0EB64F5406F63C03CD395DF2D2806661023CDD29A92735", + "v1_mic_short_salt_aes_key": "85F922D62800B1716710D7347534F076", + "v1_mic_short_salt_identity_token_hmac_key": "734B82605001AA6C8380F8D020D3B66D6CC5BF6D841CB54417FF633566EE42E4", + "v1_mic_short_salt_mic_hmac_key": "97851B6E5D32EDF9858D3261BEC3E9B6D821475F73C248EE1C82C5482C780A1D", + "v1_signature_identity_token_hmac_key": "0A209406D33340C3CB0052E913F1E9790029DA31184175D8D8E18795251EA194", + "v1_signature_section_aes_key": "C9385776AA1D74BC77CD1A7985329E16" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "7A7D", + "expanded_salt": "30C981ECC7042DDBD123DB6271F25438" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "E8591F5F7A4A9BEEFD11704A", - "extended_signed_metadata_key_hmac_key": "0D06ED71FA2DAF112A89EBA86E42961C0CCF5F114C9D5414221ACAB16493615A", - "extended_signed_section_aes_key": "5DCDDA469454FEB3C2EA71021F93C392", - "extended_unsigned_metadata_key_hmac_key": "770A74886ECB2E13C09DA386048A1FFDD32F184821CFABF97C591F2F1AF593D9", - "extended_unsigned_section_aes_key": "74093EBAD21C75C9FB6496AB55D71D10", - "extended_unsigned_section_mic_hmac_key": "528D1D684E3DBB6A55B3C74B76F12E3BF88F622796E111436F8436F9C68BD7AB", - "key_seed": "CB62878D769D49414CD07AB82DD01A567BD320BCDFE120E137EA6D24FD754A31", - "legacy_ldt_key": "526A62E198AF94F8E1C97AD51BCAD021ADE8BE68CBD16DA8FEDA9186141099AB4D1FB09B3C45E06217A50F20143C6669E024A5FF127311B46024E981A8F79C80", - "legacy_metadata_key_hmac_key": "C3FEF82D19D4198A12825C7B81D92F92A27E04C0D512FC07D2C144C48DF39A9A", - "legacy_metadata_nonce": "6A2FC44C5DCC8ECE690470BB" + "v0_identity_token_hkdf": { + "expanded_key": "4975149498F7972EE91550E2838FAA5C", + "v0_identity_token": "64357B751F939F46CB00C2E34301" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "4B93", - "expanded_salt": "0618681E330AA95ABCF5908C7D80266E" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0595", + "short_salt_nonce": "0C3874DC89E7793DA6562C3B" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "176853A104A7E84FB244044ADB23E60B", - "legacy_metadata_key": "AD1ADA1E3F33D44DBAD9D68546F8" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "854BB53F1FFAA03F8E4A4F89B36FC75A", + "derived_salt_nonce": "2B61315A2A80409D20DD3567EC8612E6", + "derived_salt_third_de": "68CFF39B8B60522BB864F55909F6A07B", + "section_extended_salt": "BE6DFEB3BC734140F9F2E7A2C514782A" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "1A605E7282BBB65E768BA802674316E4", - "derived_salt_first_section_no_de": "46EDD6B928BC45D5349843C3DA660A46", - "derived_salt_first_section_third_de": "23866A17B31C30E4B6BFCE65FF9EF2DD", - "section_salt": "CF0811E9E51806ED2EC869D2DCF7C3DD" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "D1031370C1491071F4D7C54A", - "extended_signed_metadata_key_hmac_key": "E27E04EEE22E36C87CA16C6AD7D5ADD10776EF643CE1D9CE30EB22D00A30FD59", - "extended_signed_section_aes_key": "15D907F25E7808AB08BECD25DC12BB17", - "extended_unsigned_metadata_key_hmac_key": "F3F714D219EEE49D4F2BBDEA6245570148A513989BDB07C72D940C8F6174A6C5", - "extended_unsigned_section_aes_key": "3449B21771EA3B2B1B246A73B031C67C", - "extended_unsigned_section_mic_hmac_key": "7AA8030A85FF64635D6B913A1E96D58EE649BD9E29A27F24A2EE429AADF5B6C5", - "key_seed": "FF255729FEA933CDB4EFEC5E38D382C2B8166FC1F61099FAB8E0DD472A1EA192", - "legacy_ldt_key": "95B5891E32CDD742FEFDF510C32937F19926BA8A2FF7568AA3A2049E4AC468620FB72DD2E0720EEDC69ABE700AAAD9077345CBC40B410C01F03D7B0B34EBF852", - "legacy_metadata_key_hmac_key": "B76F11E187F71D17D2A8038BBDA38DA7F6090E2CEDCF324D4DEBA899F9D39985", - "legacy_metadata_nonce": "72FE7AB45734E2C87AE34B96" + "key_seed": "926F979CD91828BAD536CFF2B68D1F78CA1D888D07A16717CFBDFB2A4305AF16", + "v0_identity_token_hmac_key": "7FEFAC357C80BE62792DDB094471D7595330063D23661E657B48A65185877295", + "v0_ldt_key": "CD2E40F2D80EFA65F2C34DB94F64FE799CCB5FEBAE1696FC8141E379FAC4E829F2EAE5D3E4512A03DFA0F00130117CE5A95EE9BF1AC6419618E8B023A2C65575", + "v0_metadata_nonce": "826FF1F5574134B44DB2629D", + "v1_metadata_nonce": "5524D245AEACC28113B5B37B", + "v1_mic_extended_salt_aes_key": "DA21A963D42360531123F21E0B1009D5", + "v1_mic_extended_salt_identity_token_hmac_key": "99E686E750515E72D124F70E05EC0A1191378885CCC98D827A8707457DAE7B62", + "v1_mic_extended_salt_mic_hmac_key": "BAEDA9CCDD8780DA6D122D777249B462D43E267A60C8AC821B6E49E52FF6E497", + "v1_mic_short_salt_aes_key": "B078CE6C132D1D5F03C7011CD1D1B739", + "v1_mic_short_salt_identity_token_hmac_key": "B2A42460F29197AA8F08367283175BDB97DDCF5716EE7F011EF7D7765336425A", + "v1_mic_short_salt_mic_hmac_key": "C774F2182514364F7FD446D14E545C6B94DAA8292BD09286B5A06320DF0E6E31", + "v1_signature_identity_token_hmac_key": "C41617580CDF1D4C81AE49774535BA6A622C319F6F02466905A13F6DFC34D354", + "v1_signature_section_aes_key": "F438355B1434789B8BA63BFA2FDB4DF4" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "3CF9", - "expanded_salt": "469C89FF0AFE6B7AEA5A94E8E5D413EF" + "v0_adv_salt_hkdf": { + "adv_salt": "F67E", + "expanded_salt": "67407A62A7D1A972E818EA6D50A4B82C" + }, + "v0_identity_token_hkdf": { + "expanded_key": "6BB8FA3FCB7F68A676918B7E274282CE", + "v0_identity_token": "A5520A470B231F19B9459DEAC5AD" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B6FC", + "short_salt_nonce": "9A22E33E298A3D2F813E947A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "34C8733D5598224EBE7E0F468AC42AE0", - "legacy_metadata_key": "B4EBC9A698A9F67B3360AB444B65" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "BB326463B805B3B120DF3A3C1EA440E5", + "derived_salt_nonce": "6D533671722212A5B388B94F462B66B0", + "derived_salt_third_de": "FCCD3C04B6AD3FBB94F5196EE5E5CB39", + "section_extended_salt": "E9E85B2DD811EFE01DB44C34D96245D7" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "6C0B7CAAB6B77D7E69927BEC4CF9857D", - "derived_salt_first_section_no_de": "E85B82E53864343FE2E11C3BBA921BE8", - "derived_salt_first_section_third_de": "B5C9E52B81072C158A44DA3D0F1B863C", - "section_salt": "55F816AB16A494DA8DB45539F30C615E" + "key_seed_hkdf": { + "key_seed": "1E886D86767B2D1CA915B5FC93342EBC806AD6514B0A6FE3BA86837E7C9BB251", + "v0_identity_token_hmac_key": "78C9838980927982C90BD31EBBFAEB6437E8C80E9815601BA8DB01AEB8D5C7D5", + "v0_ldt_key": "FB4EDFC50836341EF3902AB6838562C0AF614BA3D1D1DA817E78A98EE70517F060C059EB79126CD944E1DA5E9F577A3F82A096769D58A28909EF177697D31106", + "v0_metadata_nonce": "FBF4B4DBF353419687387277", + "v1_metadata_nonce": "08E00B2CCC92CE1C0E6E3384", + "v1_mic_extended_salt_aes_key": "00EE827633E2295F9CBF0C880DFE4CB2", + "v1_mic_extended_salt_identity_token_hmac_key": "985DC19EB9D9B8F3921B82AEB1F324C0DEDFCCE99871D5A65D1978C05B2DA1EB", + "v1_mic_extended_salt_mic_hmac_key": "DDF3D0BF099CD0A4AFC96E682BA82414775B21F69F7604CC4EEC3A70AD9F1909", + "v1_mic_short_salt_aes_key": "10D98E2BA375142D53279A7C8BAA18C9", + "v1_mic_short_salt_identity_token_hmac_key": "A3DC4E64B719FC69E60F600ECD6A6C61A1E2DBB03C936A716CDD23BA486BE5DD", + "v1_mic_short_salt_mic_hmac_key": "56FBCE7F9800AE9985C591692672ADDD87F9E97DAD409DC33A428C2DAE66D4B1", + "v1_signature_identity_token_hmac_key": "F5E639C319E632569E882D9426505E71A1E283584F4DA0CB23BE6792F4708F19", + "v1_signature_section_aes_key": "74554872D23253B364539E0DF37FD1B5" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "2C27", + "expanded_salt": "FFEC190578D4675D3E8F3B255B665B09" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "9F3A841BC948F67E6F6C1394", - "extended_signed_metadata_key_hmac_key": "1741C9FEFE5F3C189A06E18FF55693BAD6F850740AE5EE91CF0CE7E1A6A48D65", - "extended_signed_section_aes_key": "6624413BF4F1665423E6AFC7E48F6DBA", - "extended_unsigned_metadata_key_hmac_key": "79009162ED60569C88E211D09543E5612C1D5A590B8277C44F5F86A3C1ED26FD", - "extended_unsigned_section_aes_key": "4AF8134B5774E0DA661D4D74424BDC8D", - "extended_unsigned_section_mic_hmac_key": "FC55078A316070CD61B23304D7E0A076490E3425F2257503D1FA3B13F806B8DD", - "key_seed": "17D52F8EE6C17DAA338290F9E0D08F91C9BE1AB1DEA910D487309BBB09F67F0F", - "legacy_ldt_key": "F01C06D770236831C55B3A10BC648812125B0A8F65367DE7AD83E48F6EB6C2151F09F83B933B2339BD08E36DB74780BE1F435F035DE643D28CE067AF88D4E30A", - "legacy_metadata_key_hmac_key": "4BC9A35B25DA286883594B8258037CCBA46F26A76CF3D16DA66B79A5AA645FBF", - "legacy_metadata_nonce": "BAC048C167A5890EA8D5D060" + "v0_identity_token_hkdf": { + "expanded_key": "1AF203A4134F84A95EC2A465E61E6FC3", + "v0_identity_token": "B43A2C7B5909178A9FA4A81A3AF4" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "651A", - "expanded_salt": "D9C1AB2EA41BDCC8839A83CF4EFFBEA8" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "EBB5", + "short_salt_nonce": "9967714E945DD4F451DCD5D2" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "ECB322FC63A5B136F19A39403AB4A3FF", - "legacy_metadata_key": "0224F2C3F01DF3961A9DDB33D33F" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "263AC32CE6FA4D0E5F00671D461C4082", + "derived_salt_nonce": "D5216F638FB5E3148C23E3568B02DED0", + "derived_salt_third_de": "F5E3DBC571628A18F0832B3A78BB144D", + "section_extended_salt": "50AAE9055970B5F6A79554148AFF1C67" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "9BCC1DE1FB74CC1CD16D0B4200B04D30", - "derived_salt_first_section_no_de": "9ECDB554F3EF801381DB9373B9886BFB", - "derived_salt_first_section_third_de": "B898A171766659C0B6CFD5A54D7D3ED6", - "section_salt": "12120586C731008F58E2EBE90F2D9FD7" + "key_seed_hkdf": { + "key_seed": "E6B40DA9CA1C23164262097414042F425448D4A63997DF8AF14FD97078365506", + "v0_identity_token_hmac_key": "9A47EAB582881AAA20B3E09F318008A01C2978ACD715BE8470399821D44B22A3", + "v0_ldt_key": "A83EE2141E4896FDF7E0E50F47162919E6837B02A778BE6C77EF84F06425231C7E6F66A403BDE3AB706D394392F8B215E2E1B6F8B135E7FFE487F8EEA553D5C3", + "v0_metadata_nonce": "78FA2208BF4A129F35882DA6", + "v1_metadata_nonce": "74E88D1A4199CAB29AFD006E", + "v1_mic_extended_salt_aes_key": "0B080F62AE2FBAA92991B9381E5BFBCE", + "v1_mic_extended_salt_identity_token_hmac_key": "B3AD5C680CB808670B08AE7B3136A329CA755AA266086020CB13F5445D3AB90F", + "v1_mic_extended_salt_mic_hmac_key": "3D035169BBBADA723E634DCF0E203D7D0F85ABAA4DADC4C33D1DB14908C31D1B", + "v1_mic_short_salt_aes_key": "54AF93FD026428575900009294AF21DA", + "v1_mic_short_salt_identity_token_hmac_key": "B4F6A45A822954C251F04E5F54CCAC07FAD0826B5C323F4A9D2755E0E184893F", + "v1_mic_short_salt_mic_hmac_key": "6A8B6CAA0F30C013A40BE4535FA727FE47A832C4BAE0878E72ECE9DAC538807D", + "v1_signature_identity_token_hmac_key": "2EBBD9FA35E24808B06361017D2ED29263F9BD857595AEFC4336740485D3AA41", + "v1_signature_section_aes_key": "44C1F00F21E21DE548332224F191B56A" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "8C48", + "expanded_salt": "92DA955A90A7A181E9A744C7F64FCFB1" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "43EC170E0B76202475557760", - "extended_signed_metadata_key_hmac_key": "99B0F78F43A68D4F6367ED11338BD73DA00CAD40BCC917DC0E10CD1D3B8225FC", - "extended_signed_section_aes_key": "FDB4A65AC4DB43107994369895BB7340", - "extended_unsigned_metadata_key_hmac_key": "A4E32E714DBCC3AF4BB2054620ED0E26B05A00235AA46DE36E87DD1C33ED4B02", - "extended_unsigned_section_aes_key": "3A50203C921E126E8D1B0A31660E025D", - "extended_unsigned_section_mic_hmac_key": "F722C6EA33D7F8257B668A6A48AD451E90292DA2B5C5A2565383AABB3B75B158", - "key_seed": "DB33ED53F748F16D4C44A0D7256951E46737473A2ABEA4FF1A66166072D198A4", - "legacy_ldt_key": "4679142868B7A72EAE5D275C6077F84BF4A2AEF5A6B638925752B30C9A43F356CEBD1000C540CD5103F5FCF620E11FEE9900D951667026D68770E1CC9F37F9B7", - "legacy_metadata_key_hmac_key": "B81CE82EC7918F849BD209F9CBE4F6232FCC22FE773D96A7823468BD9FE6F6BF", - "legacy_metadata_nonce": "4DEC4087D83773E0A57AD6DC" + "v0_identity_token_hkdf": { + "expanded_key": "C60CB21C78BAFD9ED8A08E18C3DC9C1C", + "v0_identity_token": "B08BC761A0A1F9C72DCAC3168AF6" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "C854", - "expanded_salt": "7F509331897315561AE87E8E465731D5" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8561", + "short_salt_nonce": "A8A5A0D023F982987C6C2912" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "445F1AC997B6F6258C04D6612730F576", - "legacy_metadata_key": "5A0395FCA63385D863B94C161830" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "731880CCE113A561F779D98EC3BED041", + "derived_salt_nonce": "1C3A582B0B0E6461B150A1559F122B76", + "derived_salt_third_de": "374E30A969CBB37DFDDE376E217E4427", + "section_extended_salt": "FD6B1023E870A6908EDA3CD8067004BC" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C5D4701E3941FA12EBDFE7EAF8D1103D", - "derived_salt_first_section_no_de": "CA9740A690C83B28BB8EB6C99A28471B", - "derived_salt_first_section_third_de": "0C2ACC54B8EB3433574E87CC03090508", - "section_salt": "1420CFC23918397B5B0743A7BD1D33DE" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "2AE39BFE66BFF7F3685B7FFC", - "extended_signed_metadata_key_hmac_key": "1E5B00AADD20BEF97BB6CA33F97C20661F041FF73DB72D33787C374028FBDAB5", - "extended_signed_section_aes_key": "59A55BB848376BB2A1F2212E954743C4", - "extended_unsigned_metadata_key_hmac_key": "A33A337FC8BF0C5C435B46121BE28F5D119617D044C990ECDC61A36F8EF60808", - "extended_unsigned_section_aes_key": "4B6F0EA5C9C9A1DBC1203B0B5AA1D81C", - "extended_unsigned_section_mic_hmac_key": "D5B603436CA006324D83AE5020DAC7BD98F9E05EF3E94BA41F63558E2282FED2", - "key_seed": "0982F189CB2F763A17D3D68430CA8DE5C22D6B44C21881CF76473C21F4CF573F", - "legacy_ldt_key": "C61EEED8BF13DC405DFB8C57232F66381B7FF78CDFD4DA1FFB6737565E5419E98EB38C237064656DB9BC31611F4C47864D54DEB96CEE29F4BE9BFA8CA257D036", - "legacy_metadata_key_hmac_key": "DB9E4BF67F914548B813C071B42B37A486B1564DEB98D90CF8B4A020DB9A2702", - "legacy_metadata_nonce": "3BBD17F0F4C43E279C69A7E0" + "key_seed": "B800FA4783D4EC4D80AAD9A805AD0F9CD1C26BAD38FC5655A8755A7768505014", + "v0_identity_token_hmac_key": "F1DD45F4F5C19D4344F7CB0C04F4EF5E5BF8B417A11E3140006A4F4CA2060652", + "v0_ldt_key": "B185F3EF5EDFE2F2B722A0DCB9904AB533A12585B6A3AA897FBCBD3B435BDA5EAA9E5A76C95D64C993C36687807C1DBC5846E9A9C2C386129FE9DA39AB237788", + "v0_metadata_nonce": "6EB8B910DC2F0094CAA873C3", + "v1_metadata_nonce": "600080C27BA115C7317BD754", + "v1_mic_extended_salt_aes_key": "B16E94AC636F789C62A35DE4F974319B", + "v1_mic_extended_salt_identity_token_hmac_key": "47E5B25A33520F10E5FEFD1DA06E0908B671CAE8CAB54C5B40BE9541C5E18E97", + "v1_mic_extended_salt_mic_hmac_key": "3CED276A31CCFB412EF3E22B0E048907CD73A2BF39955B7C73EFB295689469A5", + "v1_mic_short_salt_aes_key": "9DCD2E8874EE2E6A092618AFAF397D20", + "v1_mic_short_salt_identity_token_hmac_key": "284F83827CAC37A22DC0CC2A3F10BDAC8A0E3859218C5DD5FF1F6277268FAD3D", + "v1_mic_short_salt_mic_hmac_key": "77FAA24269AE6A5A4B61569DCAF8AA75B155C8D483F32AA26ADDAC49C3AFB3EC", + "v1_signature_identity_token_hmac_key": "FF533E6454F471C4D5AE1CBE51A085082147480E06881A193CA0375D30305247", + "v1_signature_section_aes_key": "E0AA39A3E2D60041A8956A6B8A3FE4E4" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "065F", - "expanded_salt": "1360903389867A3F865080EE99218A93" + "v0_adv_salt_hkdf": { + "adv_salt": "BB3E", + "expanded_salt": "930D14EDDC1B681C49C2B315D3E89E16" + }, + "v0_identity_token_hkdf": { + "expanded_key": "F498977D3CD6C519A4BF36C1C10A2272", + "v0_identity_token": "3B0DA1390CC2F8F53F5812FE80B2" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "468A", + "short_salt_nonce": "147C2526D096E43BFB972E05" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "13D9CD7AB4481EC78AAE713AC7F7A534", - "legacy_metadata_key": "13A49EE19095CFD061978BE2DA07" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "0E396FA0163DD119AF3097362E838146", + "derived_salt_nonce": "6B87889DA7443CA9F8D9526ED9C86B14", + "derived_salt_third_de": "9E91F27B911BF1CF6CBE13CF1BF43338", + "section_extended_salt": "72B71CE5E6A3534C17A0A3BDE29FBE0B" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "5809826FE4C41311D0DF8490071E4BA5", - "derived_salt_first_section_no_de": "B10FE9FE08BB71AAEF17701E3805E337", - "derived_salt_first_section_third_de": "5C8C4CFD85E659D2CCC0A735E4C14C44", - "section_salt": "C1290354344488D39DD88998567BFA1E" + "key_seed_hkdf": { + "key_seed": "3E847398512F2295877A52FC6693C509A77D284B831AC46D17A35463141BB380", + "v0_identity_token_hmac_key": "9608CC1C06C3CF935FA9AD9576F7B0699C01190CA821A8BAEB3C196168DB7282", + "v0_ldt_key": "68803069E994A0549B92D48777B90B4ACAA691CB67EFD7407273A731C15E8DAD6705780FEB3F9776F22AE3313277E8A393EDAE23802EF457506152A082F9B2DE", + "v0_metadata_nonce": "575FF3DD58EABC3013DC3FDB", + "v1_metadata_nonce": "DF4C249AEAF7B8651989EE33", + "v1_mic_extended_salt_aes_key": "E7AD78F689F894E6415BA5A7538A6B8F", + "v1_mic_extended_salt_identity_token_hmac_key": "BB2FA7C1AF13564D37339BF793F69588259FE5F5744165C9DA3A2DCC31BC4DDF", + "v1_mic_extended_salt_mic_hmac_key": "A2B891CA3E764C78518ECB419C76EB9696F5B5489B7DAA59246A775C175AE8CB", + "v1_mic_short_salt_aes_key": "F511DCF5E5239F6F001CCEA3582BC561", + "v1_mic_short_salt_identity_token_hmac_key": "22C4B6CB1135E483F7703A06BC9F71BE65CC7901215DD30047F86ADAAFFF2216", + "v1_mic_short_salt_mic_hmac_key": "14D1B893A3947846911168A2AD7BF475D5B10B3AED3E16EB13B82A6AE9E3D5ED", + "v1_signature_identity_token_hmac_key": "2818C76B7C6BBC90069219FD3C9B3630A35582813A71627B00D6C255DE831655", + "v1_signature_section_aes_key": "AC76472156646E7D1F1E7DEB26409B8F" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "08A7", + "expanded_salt": "F848BC5C8A9B08E012A03B3A142F90E4" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "A0A936CA136E8ECA670708EB", - "extended_signed_metadata_key_hmac_key": "27200867B9446FAEC18E4B472C0C2A43D8180753607B42B678184CC5CA3B1AB1", - "extended_signed_section_aes_key": "2214D4050FEBA4E4C18543FD920D15C4", - "extended_unsigned_metadata_key_hmac_key": "51EE6B49F353568E055B06CFB717A8A467DEE6D90A6D5B325052DFFA15564C6E", - "extended_unsigned_section_aes_key": "6F162714F3BDA65324EBBC4B328CD0CE", - "extended_unsigned_section_mic_hmac_key": "DA51358ED2AA0916325399E9A2B0244D1791A1C5D600AFD8A351BBCADBE616EA", - "key_seed": "8EDCDDAE0F2742D381A7E56284E6804AC68080F872F6A587DE4DADC5B589A4A5", - "legacy_ldt_key": "6AC852D94DAFB8C18917A6406D3E8364125F01B03D1EC583FD20E5F9B71DD579B807D3874C4B3AB0FD9582F505E558C98F3E96F609636AAEAB90E9DE51703CA8", - "legacy_metadata_key_hmac_key": "89D14E7C13E4B33BDA2B0A70AFC4376FC82BC5E8B6D028F1C91D0E9159F9D549", - "legacy_metadata_nonce": "CDD93F6D02D83D0685DF0729" + "v0_identity_token_hkdf": { + "expanded_key": "395560A60B904BDE2A963527473696C2", + "v0_identity_token": "8C8B58E7FACCD45E79BF08405433" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5E81", - "expanded_salt": "A1D53BE4EC3D0418587BD370BEFC413A" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "D46A", + "short_salt_nonce": "E74FA992910E3A0F20733446" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "39B757F61E136408F7D8CD58DBAE1A89", - "legacy_metadata_key": "F58C1AE45F74112200878EB16AD2" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "BE63ECA3139C3A520E562C416E4BD42A", + "derived_salt_nonce": "77699741250F48BC8D6C3C275C7129B9", + "derived_salt_third_de": "2D57D9556AF4D0076136D20FDBBBE600", + "section_extended_salt": "CF0DCBFE60B56E6199A39F86BA47CCEE" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "4B9D669E994848CF832475821E5BA9A0", - "derived_salt_first_section_no_de": "B0DD4242F201361D92B775C5F192C979", - "derived_salt_first_section_third_de": "E5A6AE615AE988C06CEAB18846B5F659", - "section_salt": "33CC65E1EC1CE33B169733DC3096B450" + "key_seed_hkdf": { + "key_seed": "F4FE47350546180E8E5343E508933EAE003797A3CDE161DEC844E9BD0EBE8361", + "v0_identity_token_hmac_key": "472974F3E94D84F6C1BF3D2F805DA381AA033B333B012F16F8EBCE6264E8B028", + "v0_ldt_key": "515D9B38BF19EBAD10149CC42317B96796B74284F7EA8C15E4F163A37C8FE16FF756F76AC6C460A513CDC0738886B0D2E472525762810A86D84D0CB8CAA23226", + "v0_metadata_nonce": "C7DD8B64D78078D2F303EA8C", + "v1_metadata_nonce": "817FBD157903FEB877409931", + "v1_mic_extended_salt_aes_key": "A9CAB585445FE1CEDBC7A2B8F1C83C25", + "v1_mic_extended_salt_identity_token_hmac_key": "D5BC4A745CBEDC33F297CFDA6D1BD14C8DCE74F9AC6CBC8D5EB1D96A5DFEDA3C", + "v1_mic_extended_salt_mic_hmac_key": "8E377E6E535A84940C721E088559D3AABA4F448464DCE43227B446E8DE373E01", + "v1_mic_short_salt_aes_key": "0CDBB34EE71BF6F99ED10A8DDB0A3D2C", + "v1_mic_short_salt_identity_token_hmac_key": "C3A22D602232DF672FEC71BA616D49C882E9F6140379629A38DCA2DDD8BFB394", + "v1_mic_short_salt_mic_hmac_key": "CE5169D9EC16AF2D039574A47BD1B892A57AB874A214BDE3C9F078CC527F9EA1", + "v1_signature_identity_token_hmac_key": "4DF918930A3D2DC8871481B4FEB538331D57759E6F0A9407A06D15CF05809EE2", + "v1_signature_section_aes_key": "756B3BC24AB2B332F46A02620630465D" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "8F23", + "expanded_salt": "473F3FA8970C09B7EDBBF7736DED37D8" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "DDBF503438D36104DA4B319D", - "extended_signed_metadata_key_hmac_key": "DB2C6A4EEBCA496FE06C311A8A26AB0C208E2785ACC33A02AEB4ABC1FFC8E5BB", - "extended_signed_section_aes_key": "8E5E7C2C79A489BA786B7FBA6B85383B", - "extended_unsigned_metadata_key_hmac_key": "803D250E88446724C7192F9BBBB5F1E4EBA342D5391DC8CB8FF53349D4E8DB67", - "extended_unsigned_section_aes_key": "58C6E7AFDBC57C0482C6E611EF1A346E", - "extended_unsigned_section_mic_hmac_key": "D704D0EC34F6D775C575D3C09AE34A5CC1926C88E59A4DDE6A8B5E0FAC2AD3F0", - "key_seed": "EFBE104969A3580E48A63285BFA56DB95CAF3C81137B5DEDA8BBC0ACC12C658E", - "legacy_ldt_key": "382BC725B508E73E5616B110C92CD8F55CEAF87EB9E0E5BC372150AD9BEE1F1647F3944E3171519B94249A3A789D472C9961FD675653927D1DFE345FF3266358", - "legacy_metadata_key_hmac_key": "8D6251503286E357F6EC394CC68446A36BD0C62D50F20FAC6C258B3DF1FACC4D", - "legacy_metadata_nonce": "A19B0D2A97B7F3B3CC296F97" + "v0_identity_token_hkdf": { + "expanded_key": "DB6746C617AAD634961C3A864D996DEF", + "v0_identity_token": "EB699C1CF261CA6323DA7797BBE2" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5FC9", - "expanded_salt": "C69D7BCD94B23FBD8E2AC68B96330BF5" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "BF2E", + "short_salt_nonce": "EC8FC7EE9EF97564C0478CFD" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "6AFDFA46631667385F2C5D764E5301C7", - "legacy_metadata_key": "062743EDE5C56F5130998BADF2D0" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "5DC4750A1046E2318D30B4B2612F4DDA", + "derived_salt_nonce": "AC3C59C2FB8EBABD7150FD5B35F87323", + "derived_salt_third_de": "12C1E5CB114FA19F099E4E49C729B365", + "section_extended_salt": "2F130A2F720D4DA91B4C0AAC8B3F2F1F" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "58552F903E39FAD1B6FF06B7E55835B0", - "derived_salt_first_section_no_de": "586199F442C8473B9690A6AEAC36A405", - "derived_salt_first_section_third_de": "B69365658EE47B79809645ACBD160173", - "section_salt": "D08A6947309047818E4529E4CC80F9E2" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "1C2BD072C9330CB6D3807B9F", - "extended_signed_metadata_key_hmac_key": "7EB76208F558DB04B0ED9C741F7F4146AD323ED5A9676708F3C2718FCF61DD5D", - "extended_signed_section_aes_key": "9E043B7A0F1D242100D98F88D77180D1", - "extended_unsigned_metadata_key_hmac_key": "4D6397EEC391828BA27EA7E0F01DCB8350A081577CC0DF9FA3C244CACA923EC5", - "extended_unsigned_section_aes_key": "13D8B05613887623BFC72CB4BD57D0DD", - "extended_unsigned_section_mic_hmac_key": "249A8EFEEF21C7597AB5EAAABA00536ADD7F2D57CDB1C7F81914946748922B30", - "key_seed": "C952629EA0AAF16EDF450AB792C0FDF454B3748F14F8228CA39B3AC3D733BCC8", - "legacy_ldt_key": "7D90190372B6EB72DE892F159FD90C723D0B30CD1F97D7A6C15536C8766335AF62DD0BFD8FCB33CF808EA9A8565EA8AEE60D03B9A21849C7473B5E653DD58E94", - "legacy_metadata_key_hmac_key": "C02E17C17A1E010FB5F8B34E104B6F4B83C3697CE3878896D9C1D8E12128F28A", - "legacy_metadata_nonce": "D2834CF3DD852C5D65EF47AF" + "key_seed": "C299CC5A114DD4BA0600008349117F85F67333E87C01E772726CA97BA744365A", + "v0_identity_token_hmac_key": "86E6D0B6D73CFF4FC2EE2E16D4807D9BE50279BD23514BE123CD273C514451C3", + "v0_ldt_key": "1F8AB48896AB2E840310BE0A100EF4CCC8C54576C9C78EC9F433E152CF15D763F766E235198AA702E4BE714D605B773B4E1A6877EC85C2623CAA01C5A9BF8F61", + "v0_metadata_nonce": "440BC42EEED871404EAC99D5", + "v1_metadata_nonce": "7D8330F7E71F245D8C020753", + "v1_mic_extended_salt_aes_key": "45AD1594A7C622CE770C2D754E5F57B0", + "v1_mic_extended_salt_identity_token_hmac_key": "1C7636E375A0BD3ED90FFE231977CDFAA8E392C6A77890BE59C4D9877719194B", + "v1_mic_extended_salt_mic_hmac_key": "F4C3B085E1887428A07A2EF526B4C54AABDC6A596864674297BD7225FC2BA7AA", + "v1_mic_short_salt_aes_key": "19FFFA58D00FE48FC03D4D5D6ABC1D4E", + "v1_mic_short_salt_identity_token_hmac_key": "31D79DD4EDB7BE05562955557ADD32358760D9AE327656F563DF31311AD4D2DA", + "v1_mic_short_salt_mic_hmac_key": "38846B9D18CEF86540E5F2D2C94E791B1756EB5BB3EEB9D28EF5E60B32D33C8F", + "v1_signature_identity_token_hmac_key": "2C78F12CB4F9F423FD2143027E04BEFC493FBE189AC118EC4E5BF6E2E2BC6328", + "v1_signature_section_aes_key": "B8E3B89FE6CB6F9983469499A29084BA" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "79A5", - "expanded_salt": "18FB4E698A2B0F8FEEAE8D6571217051" + "v0_adv_salt_hkdf": { + "adv_salt": "7AF8", + "expanded_salt": "D672F8F7DC19AE5A881214BC736A76D7" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "359493D5139411922367E5C050162264", - "legacy_metadata_key": "579718BBEB70558182C85652E2FB" + "v0_identity_token_hkdf": { + "expanded_key": "BEB747A470A9DA803D1BAF126C3EC943", + "v0_identity_token": "5A0CEE752584C7D960B4992E05F4" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "56AB", + "short_salt_nonce": "D61316F899E53429A2D50DB3" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "70972284567C448B649644F5B6EAB7EB", + "derived_salt_nonce": "CBF23EE5038C1D5C1D3CB7B1BF408DDF", + "derived_salt_third_de": "D99B02CA713BA66DC867CC60D2500875", + "section_extended_salt": "4C5CD144852DF461550C19312FDE138C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "81083ED8ADE4D6E6EBFEC991A837AC97", - "derived_salt_first_section_no_de": "8BDCE6C08C41DDB5EF3990EE1962965F", - "derived_salt_first_section_third_de": "6451CAC1C77CDD02F6339AC8F5011935", - "section_salt": "19E1A6466DF15274E28FD2AA96C01BB0" + "key_seed_hkdf": { + "key_seed": "BF2CD3D625C9ABEB44B0789D4BBF5A7BD4BE3A4B5A19DF04E103369C8FBD4F2D", + "v0_identity_token_hmac_key": "81950F013B4A13F7EF5B5D0B291C6EE4B1C62F911F3AD01F30B37699AE21BAE7", + "v0_ldt_key": "64489F1C234BBFE2217683F96A98B35E5BA4F4515DC6449EC5A711F4248D637F79AF342661904FA8B60DFF457BC879ADA4AC1CF5E73646F201E07594E58C316B", + "v0_metadata_nonce": "E48B58BEAD817E906CB7BE7F", + "v1_metadata_nonce": "89D0D8C13576F46B74195B51", + "v1_mic_extended_salt_aes_key": "CB093E649CF4ED1BA952819C983B0A49", + "v1_mic_extended_salt_identity_token_hmac_key": "F8D27C142C1879957C7B0FEABA93097D1AB2F1FE6CE2B4A780EF3B7E12A7A270", + "v1_mic_extended_salt_mic_hmac_key": "726C6770FD205CD85F732FED55421A4DB1D7F861E028AE144E883FA88128E099", + "v1_mic_short_salt_aes_key": "0CF33F93B242A4095821CFF75ECB9A95", + "v1_mic_short_salt_identity_token_hmac_key": "A0E1E2FADA968696B8A421D348021783D41BF5B92A8A61CBABAA3A605706FD70", + "v1_mic_short_salt_mic_hmac_key": "32774F6FC589A6A0F3C57D3A3FBDEAAA8C94CE31BC1BE2E71A770C29A365E8C1", + "v1_signature_identity_token_hmac_key": "3FA4A5EE8D7CB441D33519D371B615733E82CD99CE5DF704B4BEFFF525B5D484", + "v1_signature_section_aes_key": "A69439EEE9E503DC46CDDB7220E6C1BF" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "C47EAAC92D0E2BC76D5B7168", - "extended_signed_metadata_key_hmac_key": "8666FC7A47A63BAB78216CE4225E819D8680DB8C6F79F3FFBFB8B573C0A35C95", - "extended_signed_section_aes_key": "E4CFAEF9DAA97426A0F6776ABBDD0615", - "extended_unsigned_metadata_key_hmac_key": "18B3DA3C8736739FBD9D203493BC7697E47EC2072DE351475F332A989CCE2600", - "extended_unsigned_section_aes_key": "3732E014F15539C1999F6486B7933A43", - "extended_unsigned_section_mic_hmac_key": "F0ABA5CC299B1D3C210774DA1B065BCBB877A0991EED7C34E1DF5B318D1D5C25", - "key_seed": "E49335220345649BE4C6AD75B3EDE2A49A9CD22D291764E90510826835CA3528", - "legacy_ldt_key": "637CA1A46B169B80D0833678505E3FBEBDDCD42C7D297E78EC5DD6CE1F8007914742F09396A5439592568445117436BBF0B8A4075BE65843259B28A49C8C4A3F", - "legacy_metadata_key_hmac_key": "1780831E70950E84CEDBB6D08591E5867DB33D64B9AEFC60C1D29D3F4BD0DB6A", - "legacy_metadata_nonce": "4FE56B42C34913314149EAD3" + "v0_adv_salt_hkdf": { + "adv_salt": "DBA9", + "expanded_salt": "D67693A7826F8BD42315C68A72C5FF35" + }, + "v0_identity_token_hkdf": { + "expanded_key": "EAAB13D180BC7816E235F2D5CCE25C5F", + "v0_identity_token": "953C70D3F668A9BF305EA11FA5A5" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7369", - "expanded_salt": "7B7D59EA9882AC8D8E5B95F11ED6773B" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9443", + "short_salt_nonce": "EFDA8286D9A7A9B08A098C9E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "20D2CA28DAD44F40276871C7B8AD6D1A", - "legacy_metadata_key": "AD5DBAB68501DADA871E6CE6EFF0" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "932952F0056579BD3532A369D60A6F70", + "derived_salt_nonce": "0F8B66EE0EF87D7B6BE39BF707378448", + "derived_salt_third_de": "DED92B09B5BC920A8AECE3DB8C7AA0C1", + "section_extended_salt": "CDA0859A2285EADBE17556BD28F0D67F" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C27C4FA03E43A46EADAC3A827A6ABDA1", - "derived_salt_first_section_no_de": "28B6CEF526584124B03720FC4A65188B", - "derived_salt_first_section_third_de": "76B42830B3813795F19CF07B6EFD17C8", - "section_salt": "3DAC056F62D259B969B815D08DA79507" + "key_seed_hkdf": { + "key_seed": "C759E0D5EFFC5ACB780EE1FF77B2B82808A4418F5103FCDE125ACBDA1CE010C4", + "v0_identity_token_hmac_key": "894B0D42B56405F75E28594CAA888EFFE173A6399B892C4AD6DBE49A197E3522", + "v0_ldt_key": "8DC248F5B78A21E5F1178157EFA2933ED5A57FAD965560FCB039FB41271AB5CC26FE160E3FB179E5DC04C15E51EFD2A13F4E861F3E85889457C8ACB0CE8FA4E0", + "v0_metadata_nonce": "988562C19FAF889DA9390D3A", + "v1_metadata_nonce": "1EDCB2F7F9D00FCCE80BEBE6", + "v1_mic_extended_salt_aes_key": "159A387D0884959C1E2EB955EBCE035C", + "v1_mic_extended_salt_identity_token_hmac_key": "5646920E0104AB7CB77AB3391A61FF420129C1F499B13CA122DA6C77A3BA7728", + "v1_mic_extended_salt_mic_hmac_key": "2B2F8575D91F2B3964DAB5721DDED08B8C12AE5C0B984DEF3363994729661130", + "v1_mic_short_salt_aes_key": "EDE131CD4C8D0F1251E92C3A3BFF7BE0", + "v1_mic_short_salt_identity_token_hmac_key": "DF5823CB7AFD4442A6BC99342B13B9A94343570D487F47F99B15B41131FDC291", + "v1_mic_short_salt_mic_hmac_key": "729CDAF9889B1465960C519EA7C5A2D93ECDCF08A252047125284A6A4AFB8423", + "v1_signature_identity_token_hmac_key": "DFD3C298F8D8AA5091667EA7DA56C1749259021B5D046E18FCF11515606605EC", + "v1_signature_section_aes_key": "1F0821DA6799721FF225950245DC62A2" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "8BC4D291417DA2637FDCA948", - "extended_signed_metadata_key_hmac_key": "69305759C5CF4AD06490F51BF9305543E835A219F53EA84F39ABF714F6B2F855", - "extended_signed_section_aes_key": "69E4C6301882A5494C10231DD82FD9AB", - "extended_unsigned_metadata_key_hmac_key": "F6F45381D06AD669756F4BC421495F60F02FAA2FFD3ACF9FAE6755CE54AEEA0C", - "extended_unsigned_section_aes_key": "744A7950D65D03AEEF5AF17C36AC3954", - "extended_unsigned_section_mic_hmac_key": "AF012F292628BFCB7421B4A846361AD4829FB93FD766A014A5D846B7F471F5A8", - "key_seed": "B46750D2A75BDF9960E825289F24D8A1C777C4481FDE9E1E38F72A3DF7B29AEA", - "legacy_ldt_key": "7C689AF4CE7D769DEC4BE41DE5651B9C87F76D988C90DF4A5263859159CF855DCEFEA5B0047F450AE9033FE5E3C4D96D0B81DA5D52C94487C481C11BC5204A71", - "legacy_metadata_key_hmac_key": "4EFEB0DFFB5E37BF0BE1373A4917078FE2F54EAAC0E22CD049D3A84F79CD5BCA", - "legacy_metadata_nonce": "0185B0580338EA6BD57D801E" + "v0_adv_salt_hkdf": { + "adv_salt": "4BF9", + "expanded_salt": "F27CC32AEDDAFE2FC02FC67785977931" + }, + "v0_identity_token_hkdf": { + "expanded_key": "F857C81818AD95DAA7A218B71493D27D", + "v0_identity_token": "1CC5F7109208CCEF51918F37A789" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "4456", - "expanded_salt": "4C0B15F195F4E9506FD3BF692C8A81A9" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0E95", + "short_salt_nonce": "8D12E132EB3558CB5A2A1A0F" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "F7B19B1F77FDDDA49AD637F92F559434", - "legacy_metadata_key": "71C96FDFE7539BAA0A52B6F4C1ED" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "A568C7960F41860E4CD438B7E09DA45C", + "derived_salt_nonce": "82003458C32B5E1408B98668BAFCC9C4", + "derived_salt_third_de": "BC2E3F5E799FF967924D4C31E7A8A0C7", + "section_extended_salt": "CCC4AE71E0147BB16F2EBCCDB9FE31A1" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "DB0238E42DD58FFCEF52697A6B60EEAC", - "derived_salt_first_section_no_de": "76B8797D8220B4F7D3F2994F57AF40F6", - "derived_salt_first_section_third_de": "8FEFF73B163E9ECBF0B75743237146C2", - "section_salt": "3FF3074E6E32C3A1282DA7E7486FD5D2" + "key_seed_hkdf": { + "key_seed": "398915BD66C14A84D4FDCD43C8F1DE6C8CF2BC38022B46C3628F3180D0D9C479", + "v0_identity_token_hmac_key": "91447A689F29B11D432DB5A28780ADEA084956BCA2F39040C5DC583036935EDA", + "v0_ldt_key": "B7DCF4BDF2590C365200462F2740B1A25108D174F2DD489D0B3AD0D60DA354E884A5FF038167D780A855C04B5991F37554BEB0D5D199C35F929601B38ECE4C0D", + "v0_metadata_nonce": "BEFC1162FFC2D7B05AE4721C", + "v1_metadata_nonce": "ABBEE58AA1A5C5902A66CDEA", + "v1_mic_extended_salt_aes_key": "49D90757E91DE84386B7606327779E1E", + "v1_mic_extended_salt_identity_token_hmac_key": "F2E067C282FAA0C1EB289976ADF992BC5C4774E0830E9D90F195259A859FD06B", + "v1_mic_extended_salt_mic_hmac_key": "905E498FA9444EFC1C23D87B1A48DFF08CD0F71199F5D4A33B0A8D9C03B687FA", + "v1_mic_short_salt_aes_key": "D023099AA0859DBB1547E3736DA4D22F", + "v1_mic_short_salt_identity_token_hmac_key": "9446AD8F40DE7801AE8C05F4198221C4545836FAFADCFB6A9F6B6811C17320C8", + "v1_mic_short_salt_mic_hmac_key": "2F437832F6F6055F3D9FC22E1FF89071C579F9261B200B1289E40BD1987FCE62", + "v1_signature_identity_token_hmac_key": "08DEBDA02FDB8250E3B6DD38CB14E6423F414733847634154DA243A0A48709CF", + "v1_signature_section_aes_key": "5AE2258B089A53E623FDE10A849660B9" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "45BD", + "expanded_salt": "3028028A24AC94FF0DB3D424F09D8E32" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "8E1A231A33610A9B3F78D046", - "extended_signed_metadata_key_hmac_key": "724CBBC4F7B44408327A62B1EF12BBC451732406FE77B1F7E6F5EB125D47F69D", - "extended_signed_section_aes_key": "EADDEDCCE98E6DC2145C48C5648052A8", - "extended_unsigned_metadata_key_hmac_key": "9519CC0F24A2DB8D534B9233E863D1105711E79E84DFBE17E13DC3D6C1332D2A", - "extended_unsigned_section_aes_key": "80C1210F4F306D881C7ED5568A78D643", - "extended_unsigned_section_mic_hmac_key": "590362F05927596F04EEE3633FD526DA7C17FBA4A4489DC1B09F33FA2A84DACC", - "key_seed": "D83D79192D3A1490BB2DF4F72686E8E351F5F354BBEDB83B389DBC94D0DECC6F", - "legacy_ldt_key": "F6CC44D2FB8A497FDEF4D8505BF8954C1673F7AA74279938FF60D74F2D56E5E590B1EA7E71EEE7A14782FB6E5DDF856402DE2F388BC7A6BE7808C6B02D6AF3CF", - "legacy_metadata_key_hmac_key": "8EC62082A556856D8D9622063340E8B7A649CBB82193EE3FF1980DB7918A74C8", - "legacy_metadata_nonce": "0AE81376D41C4A66A58C9E15" + "v0_identity_token_hkdf": { + "expanded_key": "FA406BC38B6852DBA58B830C9669BA49", + "v0_identity_token": "D2E0463D56277A2CF9CC5BA5F85B" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7538", - "expanded_salt": "9C0EAC987D64D64324502964CE4260AD" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9C48", + "short_salt_nonce": "DBC275D67654EFB6ECE3CB2A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "809FF61B6778348B260BFB91DB789913", - "legacy_metadata_key": "BBCFBE39DF3BDF239B25E14976A5" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F1C91B43A17919A92B1A663CD5214050", + "derived_salt_nonce": "07D78BAAB0539B291E17C946F94AD5A3", + "derived_salt_third_de": "9E1D2E450EAA994518580BE3F95163D4", + "section_extended_salt": "98646141DF3AFB3FFBD4DA56C170AC50" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "86485E5604FA2EF6F8EAF42DF4CE0CF1", - "derived_salt_first_section_no_de": "5506D594D6DEBDF6AA3FF103EF018765", - "derived_salt_first_section_third_de": "DE2468D8B660E2757D9D80315450D573", - "section_salt": "C7321D6A2F9877CB0FF99B9B11D34309" + "key_seed_hkdf": { + "key_seed": "935ED1A8B2E5DA1FF777F1F0245CCE37F8BC20FF306A0A82C3F0F318E953DE3F", + "v0_identity_token_hmac_key": "5E33B312FFE3E016F7D8B319B7ED4CA72CA25755D32773210E5B758F75732BAE", + "v0_ldt_key": "B9BC506239E428193E0ADAE2705D1C5F3F75E502C45DEB393A07D095C2E1E58616548BE47F73AE0056007FEECF9D19DF78F8CBD0F0B4012BCD1E8CF45FE79506", + "v0_metadata_nonce": "F225F715CB7E592925BDFFBE", + "v1_metadata_nonce": "C07B2E089AEDCFE7E94CBEC0", + "v1_mic_extended_salt_aes_key": "E07FDEA905AAD3D0579B42F50705BFD1", + "v1_mic_extended_salt_identity_token_hmac_key": "B016136199E5127F95390815C77AAC735A585A8861CB2805543352971D62951B", + "v1_mic_extended_salt_mic_hmac_key": "87FA6DA8F450D40085241D55E17EE0F1FAB9B4C51841663CF13DF7D84A03684A", + "v1_mic_short_salt_aes_key": "603CDFF82688718D13120372589636A4", + "v1_mic_short_salt_identity_token_hmac_key": "743FE98375D1C4D41B02AA9A636A92837AB4C5A588664CECF00E216ABDA17DBE", + "v1_mic_short_salt_mic_hmac_key": "1C67FC0FE2E06FE973DD46D4DB0D72A651376F61C8CEF15002F2FB511C05C303", + "v1_signature_identity_token_hmac_key": "58B127F990B55B164990917F1C23B485F3EC847DA2E27E0D541FC6F7AD437BBC", + "v1_signature_section_aes_key": "33F90FC36D254B78F3D0A1CCE47CDF2F" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "CEF6", + "expanded_salt": "889CF5AB8E18277DE8AB9CD2FEBA35D0" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "D7D49880F809AFFDCF2AB7BF", - "extended_signed_metadata_key_hmac_key": "89280461B4D2102D3F829CBBDA32CD75F01579E2B25E8C2F01F3983804A7B5D1", - "extended_signed_section_aes_key": "9B42E858D2ED7439F951403533CAF3F0", - "extended_unsigned_metadata_key_hmac_key": "509A8BF8096E9A547D14F27284C20D7EAFDA6C9D8D0946EF81D4611DE00F22DC", - "extended_unsigned_section_aes_key": "88F058A2EAD74A4BAED5F99136508DAD", - "extended_unsigned_section_mic_hmac_key": "3729770DD90FEFA7253F53F87244C928CDE14CF5D2D5513D8EB3C1889C34AAA0", - "key_seed": "96B3E4E23374C3162E94B1701F6720E0D0918AAAF10FA0E7FCBC4D7059C824D7", - "legacy_ldt_key": "4B0AB9E1C8CDE2F1B55EE0EA4A331B8B923E34AF5DADC5F18971111F45D41BDDC7E9A9F7D28F94AC71F50DFE5AAD7FA7B85884169FE0099175073100CE1DA9C7", - "legacy_metadata_key_hmac_key": "5FE8C268D4DFCFCC91F4B7820BA679D26A54C8FF0F3063EB856BE84FF4AED8F9", - "legacy_metadata_nonce": "D885F819DB614904DEF77E09" + "v0_identity_token_hkdf": { + "expanded_key": "59B3F16B05BBE9202E78B12ACBB65F9E", + "v0_identity_token": "51B2C41F6AF7AEE74DCE977FFA71" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "3881", - "expanded_salt": "839E06D9CAFECE9EB910ECA73E7B7041" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "E664", + "short_salt_nonce": "5DE9BC53D47908F83224673A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "C4ABC2194181D14624AFE1B545E87B95", - "legacy_metadata_key": "2F8C7737B5E98216C6358DFD1163" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "4AEE99434AD2D226A375264CBAE0497D", + "derived_salt_nonce": "0F201B1E244712F3AE2B7C5DE056DE63", + "derived_salt_third_de": "282638440E3212C29F5E8654C6B8B9FA", + "section_extended_salt": "1A80A34BAC43864CB5BCFF4547F1B88A" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "A662F512F68A331133401EA5EB2A2A66", - "derived_salt_first_section_no_de": "BFE2EA19A0984DEE6BE7EB90DC2FC58E", - "derived_salt_first_section_third_de": "92E3744D86B5ED21D50C726A66ED36B5", - "section_salt": "55DA08E873B5664E175650BAAA9A8021" + "key_seed_hkdf": { + "key_seed": "C0459E6013DD6B77DAC1CAEF84BC43BE04C7E171D5725375C5EC7BFD0A37DC68", + "v0_identity_token_hmac_key": "97B9B1371244C00038A4E32022D32B3A550BFA6611BACD1D56030D8B2EA37452", + "v0_ldt_key": "A23B8AE89920C1ABFC2A0994DDD4E3E8EA83B9FEA70F81461E5D51D5BB372C674E9D3CD59D5273D9D719EDEB749BF6CD1AD077DCC1E969D5E1715F91E23E8310", + "v0_metadata_nonce": "8A33A7C387BBCC7505C32AEA", + "v1_metadata_nonce": "A4DC2C766352C27F845EFAE5", + "v1_mic_extended_salt_aes_key": "90A5BFF37C46AC0B5CFDEB75FE20980F", + "v1_mic_extended_salt_identity_token_hmac_key": "99E8E1414155D0B5B79390615E2F9F80B2F519C00944C01C19450B4AFAA90601", + "v1_mic_extended_salt_mic_hmac_key": "20C74AAE9D32359A0C9353267458581B4AFE60606060B16060591CB96AC68F97", + "v1_mic_short_salt_aes_key": "11381F1734226C3C2911C7D1280E55C9", + "v1_mic_short_salt_identity_token_hmac_key": "A4E6D4F2475E98ACB5E95D518DEA87E90B1EB7D9D2F5AA1456C609CD5B5351AF", + "v1_mic_short_salt_mic_hmac_key": "AF6150F86F8AC3AE7BA32219E7B92B158E866EF8CEB36BCEDF6DB456CBBC94BD", + "v1_signature_identity_token_hmac_key": "6D27EB4BE29E556CE5A41BB89648D91314A73D60FE884CAE79BDC811115CF08B", + "v1_signature_section_aes_key": "E5C1080FA68F5EBDD6F3D063BBE0EFD7" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "8E7098BA5E6A64E0F97746AD", - "extended_signed_metadata_key_hmac_key": "D8C3614062B4B68DFDEC328EE588C257CB5D8378F33F514181FFBAABF9C18A2C", - "extended_signed_section_aes_key": "9215527DA83060DC2F32E39048ECD4FB", - "extended_unsigned_metadata_key_hmac_key": "345516B0AFF7928137B9AF940CB13EBC734F9015540C713C0C813AD136BCAA09", - "extended_unsigned_section_aes_key": "C563004B3236B38E9C02BC6817B9B199", - "extended_unsigned_section_mic_hmac_key": "2F4A9499095C511768D57BEC00A3EC265E9384BC9A12B0F9956791D8617BBE3C", - "key_seed": "4678C5DAC152DF06265640453E53177D237E72FD58E1B784C692D95363B3DB30", - "legacy_ldt_key": "08D4D021EC845DCE579783FAA377F1B8E20A75CD4768D18DF0326F314A181C17CBB821F0033C970B8A7448E208FA06025A855D25DC38775E44917DC51CF267CE", - "legacy_metadata_key_hmac_key": "0D31EE249C7FFA7A827E90EA8C20D70CF22F5DD8DE8BA331A5B05B3831435C36", - "legacy_metadata_nonce": "DA5011061FF4017D38381053" + "v0_adv_salt_hkdf": { + "adv_salt": "DAD4", + "expanded_salt": "122911634C8C923FDF8CBCAFEEB31E6D" + }, + "v0_identity_token_hkdf": { + "expanded_key": "7B8A759E2B26F88A93F80FF05C5E5793", + "v0_identity_token": "F01DFBEDB49F8E2DF56B2A9FF832" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7C72", - "expanded_salt": "7F599F5A3FA8CA8046C80BD2F8D43377" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "31AB", + "short_salt_nonce": "D7A09F5405418C63649804EA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "77B1D1B130E78CD88DB0FB2D439722A5", - "legacy_metadata_key": "0FA76D2A99B2E693B6D358C41D42" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "C94F9B608026089CA2BF81CE363295F7", + "derived_salt_nonce": "302455E6682F71E2A813211487A3026B", + "derived_salt_third_de": "C289C64BE651B24E7365D79679EFCC46", + "section_extended_salt": "BFB748C26DD77BA9F8C82E7572B14608" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "532346C01C3D5C6488233523F1239853", - "derived_salt_first_section_no_de": "00FA8A3468172AA618AA22518A04AB90", - "derived_salt_first_section_third_de": "1B2BBA5F893D87824BD4D36EB568ADE3", - "section_salt": "F3BADB4D93D44B2C83651C4D977BDA85" + "key_seed_hkdf": { + "key_seed": "FFD07DB5B2DC2ADB24E0EDABBF6089E579704E7935A4D1B185F6AB6F4ED93B71", + "v0_identity_token_hmac_key": "263FFE0A653F56E30861B534D9826FA459972D6142542CAE3B67B6CB478EBAF8", + "v0_ldt_key": "1D85D884D12A065DD61C71B3BE3818E116346E0C9619B89960ACC88F9B8875544B682771AA2BC5ACAB33F0BFAB45F8449A236FCB9EC64688A5F7F00BB7799C3B", + "v0_metadata_nonce": "B8421CB3EE4D1BA5FB006128", + "v1_metadata_nonce": "E5CD8BD69CB8D261B5AACA5E", + "v1_mic_extended_salt_aes_key": "9C22E81DEA2F0837A050CB2A78907AE5", + "v1_mic_extended_salt_identity_token_hmac_key": "6EB2EAE0D24668E4FAAD66C88E59CAF50ACD2F932EB11DB1DD2E5FBF93C04FC5", + "v1_mic_extended_salt_mic_hmac_key": "EF9D7AC607E5B37BB21B16409556162C6EBD3DD89144F19365698FB34E06A2B1", + "v1_mic_short_salt_aes_key": "1DFE937349A0968CEA77801B8B51E743", + "v1_mic_short_salt_identity_token_hmac_key": "9D1C138B75F9D255E62CC8806D36727DF5877CD831CF6CBFA9AA1D631D032F32", + "v1_mic_short_salt_mic_hmac_key": "9D1EFDC00D17243D29DF77EAD25DD34EE1E10E420B047D7C147769A1EC149AF7", + "v1_signature_identity_token_hmac_key": "E07194FE1E11686C87A325E511C7DB7DABA3B631878CBBC2018B70F5D75B843F", + "v1_signature_section_aes_key": "34EF3FADD1EA265EA5DB45B3335862B5" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "D65B", + "expanded_salt": "47443B86F1FEAEEEA75EC5C4CCED0A59" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "AC7F3D2E8F0CA67D9E3286FB", - "extended_signed_metadata_key_hmac_key": "09F574FCD463AC6C36B8E3444B5C205D4E7F34FEE2C50F4C9D8F4E21F3F08E8D", - "extended_signed_section_aes_key": "03929B8C9D55DE8A2DB331F3A458C5A0", - "extended_unsigned_metadata_key_hmac_key": "41CB06A6ACA499582A97E506954CF3346E10922C6816893088E920400C15724A", - "extended_unsigned_section_aes_key": "8586ADD0A300F594781EC6A91F7525DC", - "extended_unsigned_section_mic_hmac_key": "0A104999429CBD6CC254840DEC399C70F9A64F4BD4B9EA572861F44280311D1C", - "key_seed": "5EA22F37C2895A5ECBEF49AA18F9BEF14E2221E8AD6B73C48B500059C0920563", - "legacy_ldt_key": "2CF083240697097DB14CCE7EC06542F2D8CA93DBF4404BF733A67BE123A7D577A4ACEAA6EAFF9BE5B73FAB9E48AAA93D63779D8FAA7044C24D1DF6E6415540D4", - "legacy_metadata_key_hmac_key": "5DF6ED321FFE805FD33A7A17CE8CB8348532798C604F3878892D3A6B1D12E4D0", - "legacy_metadata_nonce": "E9872F6F6C5595E82DE87409" + "v0_identity_token_hkdf": { + "expanded_key": "BF1DA5BA126DF4B125488BBEB78B025F", + "v0_identity_token": "A684A924CCF85EAE5A0C7FA404D0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2D24", - "expanded_salt": "09935DB3B8781070715F440E27D5CD90" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "D4C2", + "short_salt_nonce": "14E6E257738D5C3F8EA61A99" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "7B9525E023AE6563A1938D713276A250", - "legacy_metadata_key": "E95212B84FBB8BD181401FB77BCE" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "37DF3ED46159C7B50B7648454A8E3F6E", + "derived_salt_nonce": "B19C63BCBC2C5466B7CDD1DD160BC813", + "derived_salt_third_de": "7A52A770AC31BA84A31ABFA410398E39", + "section_extended_salt": "02017844CC8940E3F95FE27ABF392FDA" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "F4A7A1A0A42EE2C34BB44EE7CB7FDF50", - "derived_salt_first_section_no_de": "F13440BC0A2B7911039742C57654D2B6", - "derived_salt_first_section_third_de": "AE1A8F016C73B5BA485C27D9F21C4379", - "section_salt": "B7C7FD8E1C40228B71165C00DF490496" + "key_seed_hkdf": { + "key_seed": "5D8DED0DBEF3082DF7666EE9C6413D7099C5D57CBCB7572519AD55596351058B", + "v0_identity_token_hmac_key": "1787E7BC8CD40D4E2156FDEB481F2D100EBE29515F26D88E7C5B47E4B4CE3398", + "v0_ldt_key": "907FE054670C2DDE42021BA1CD61ED49199E6A532044A55A3C842F0761A1A7EE4D9EC192745D3117D05D6BA4199C38435678A38F09FB91A28B80012A2E494299", + "v0_metadata_nonce": "149C72A3CFC258042CBC296C", + "v1_metadata_nonce": "61D13728AAD32435EA7F2C17", + "v1_mic_extended_salt_aes_key": "8F7D7FBB86A7B76027622311BD4FC4FB", + "v1_mic_extended_salt_identity_token_hmac_key": "E6D3AF59926AE7CA978F7CE621BBEFC1830CF8E20DB29B4748F97936CBF9DE32", + "v1_mic_extended_salt_mic_hmac_key": "23736395522DF94359771CA21DE0EAD1E27AE0833A8C02ED4407DA7BC71BB971", + "v1_mic_short_salt_aes_key": "917D6DC510048504D748A1251EAC8BBC", + "v1_mic_short_salt_identity_token_hmac_key": "D247C289A7F7C16473E7A8E5F737B2F60F1F281359A2E0E5976CA13E33D0BE48", + "v1_mic_short_salt_mic_hmac_key": "D917D8FE9CE653BC8AB3109DB07377B95CD9A0E02028432ECF3B71F933AFB548", + "v1_signature_identity_token_hmac_key": "A9E65F92433276507487CCFB1318EA841496C7C1DED9B963D843F56035BF2889", + "v1_signature_section_aes_key": "714014241942077D480CBEBA5C7FDA16" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "41D7", + "expanded_salt": "D7715923CE771A66E2F806CCB655CE28" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "62E90AEC398397F92486725B", - "extended_signed_metadata_key_hmac_key": "512490244C6AFB22B8E1FF0AE15B1BD9BF61B02C20FDF18AFCC28704FAA04B11", - "extended_signed_section_aes_key": "C650084EAA3E35460C65A6D5A3BC056F", - "extended_unsigned_metadata_key_hmac_key": "969259ED1CC21D9DC198921204BD98F1B60D51E52758EF03EA42A088FC33AA99", - "extended_unsigned_section_aes_key": "A12E741FBEE73C341789F4A2E217E568", - "extended_unsigned_section_mic_hmac_key": "C11625C0E356394FA499EA6E7606CD7ED016364FC8913C2590CD04E6B7101C33", - "key_seed": "9FE70D5318CEACFFBC1C0BF66168E2404D67AC342B36AFAC5306F65AB75D4BD1", - "legacy_ldt_key": "07DB2360A6FF579827C73C33947D3432F0D2D44282C3055447C79C732A3DA4CFCA3423D87D080259F2056D9EEF0AD03D874AA6D3767019608486CCCE1CB34CAD", - "legacy_metadata_key_hmac_key": "B8EF43182F6E8159601E63E474DA30B6A0A18FAC8D37BA25207395990F75CA70", - "legacy_metadata_nonce": "B8E730D17A2B71DFD2113E80" + "v0_identity_token_hkdf": { + "expanded_key": "3E342AEB8310CBDAB633C0FFC9B0ECB7", + "v0_identity_token": "E3D4CE4C1ED84B51283AEED98978" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7141", - "expanded_salt": "9E8C5C44E412C2E5D54FB423AB48102F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "E61A", + "short_salt_nonce": "2B7D6083221050162AD11C2B" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "1FC5EA826AA0C33800219591A2856184", - "legacy_metadata_key": "DBEE14EB39323EE9CC4B341C3A00" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "1479B6AE3A8F99CC6A421B7654E82B65", + "derived_salt_nonce": "DE3F081731C6B7E3B2155922FCFBA033", + "derived_salt_third_de": "B0BF305855ED8EE892A1574BBC35F1CE", + "section_extended_salt": "4949EB4D92049664AA78BA61AD0A159F" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "BA4492E8755975045094D06AC8930F50", - "derived_salt_first_section_no_de": "20B8815C2C7788BE334D8D945AFD59DC", - "derived_salt_first_section_third_de": "2E567F8F25DF8D06C7DF61A05811F7F1", - "section_salt": "627BA43CFCB6B9FD6C4676C1102635CF" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "D1FE7EF66BC90F8B53E64538", - "extended_signed_metadata_key_hmac_key": "1484C6E96375DD5B4314600D12BCADC5063E1C865D64C8390CFF60E52E6FC0A1", - "extended_signed_section_aes_key": "CF4880570B17863BCC0B17D263BD563F", - "extended_unsigned_metadata_key_hmac_key": "E3CF564D084FEC04FC96B6CD5A23B288D49F360B326005698B6B1CBD8B8860A9", - "extended_unsigned_section_aes_key": "6193B4A238BE3240C7E4D53E7708EE8B", - "extended_unsigned_section_mic_hmac_key": "45CC2AFD5BB72392874172AC5C059E871BD6E9C46D977E6D0F7510B817B180B4", - "key_seed": "B237A0FC008DF51F15EA3E1789FC834923556B61A7BD30664EA06BE6C40169D2", - "legacy_ldt_key": "FEE50CF8496A24EB1A216C0FDBED6CB9559099E8650BEC22C2DEF7ED4E490A9CFF5E21C40572A40AA9F5FC3E9C60F60CA60C257D08155849CADCEE76FC869202", - "legacy_metadata_key_hmac_key": "8E854A8DB7B847B84862757EDC73881609F0CF90A99DBD82571C204B040B5D54", - "legacy_metadata_nonce": "F58512DCB899E1F857C3394D" + "key_seed": "529A341BF82608D457E6225E80308FBA0A33945C52B8C711AE8D114F2719090A", + "v0_identity_token_hmac_key": "BDF73B8718898BB90871292D9819BDE09EC1C7039512896A7168500FD62B7E32", + "v0_ldt_key": "3A0805FC96D98923886D637A955144BA4018728882E7D8B47059A2D7C87FDC0E5F36536B7C494EE81D0857FF5ABEC9FEA4737ADF10F87B5A93618379B3A33CB6", + "v0_metadata_nonce": "2F655577FE85379259570525", + "v1_metadata_nonce": "589FA32CE6FF284F20D05590", + "v1_mic_extended_salt_aes_key": "E7CE9469B47ABF36531D71015AED7CA7", + "v1_mic_extended_salt_identity_token_hmac_key": "37433BA485D9F7F18D29122C494E7049754ABACAF6BEA52CED98716B8AA737B8", + "v1_mic_extended_salt_mic_hmac_key": "8A46B4B1543041B78B3EB07A68F4228B439E5AB139DAD332660482C7FE902FB4", + "v1_mic_short_salt_aes_key": "C5613A5B5FE8DC12550878B35E58E2DA", + "v1_mic_short_salt_identity_token_hmac_key": "A6C66389A16F81596893F988F31B3C3EDC871378DF687B6F92C069FEC3763C56", + "v1_mic_short_salt_mic_hmac_key": "A309E0EBD1838289BE98D58062298A7BF81743511FFE526162CD57C1A5DA7CD4", + "v1_signature_identity_token_hmac_key": "2727662B707BBB86574B63B085950181C10A66E95E365BD5E4BE2BD42CFFCD23", + "v1_signature_section_aes_key": "61539D6CB1E73FC4C5234E1F505EFE83" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "770E", - "expanded_salt": "7A1A3782A82F1E40CCBD5330A84750E7" + "v0_adv_salt_hkdf": { + "adv_salt": "C590", + "expanded_salt": "9155D976B94C493E5068E87CE6DC2B07" + }, + "v0_identity_token_hkdf": { + "expanded_key": "EF3AFA04327F12137EC7ED24952AE0C6", + "v0_identity_token": "E78783E55CF00CB3C377D47D739D" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "FEC4", + "short_salt_nonce": "A58A3AB41FB65068E3B2BE23" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "C8C682033DA60D93756D23338D6427BC", - "legacy_metadata_key": "E12C6EE466A1ED61753B30E6BD6C" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "982466B94926A293CAFAD0D8DDB5E2A0", + "derived_salt_nonce": "9C14D11F87D3E49D71426882A36B793E", + "derived_salt_third_de": "53024AF2F7BEFA7D22D9F057CB75B285", + "section_extended_salt": "DCA57C5D334B5501EFA2C6C6CA66AC4E" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "B20A3B57F64EFC41D079734A14A3D576", - "derived_salt_first_section_no_de": "09B542C88D08F276B29C0E1A2A424246", - "derived_salt_first_section_third_de": "962AC562D09F20F714EB885E729D4C3E", - "section_salt": "53F5CD677966C5D1E3EC25D1089BDFF2" + "key_seed_hkdf": { + "key_seed": "77E25A3C9C6D94331B883F22A24EBE4009485DF2EB38AD4D3AD3EE445035AE92", + "v0_identity_token_hmac_key": "814E06DF65361B28EEA39EEEA07163115D3015BCA846A3897604B932A07DE31D", + "v0_ldt_key": "0559FC378F7A5013C179B9F39D31D5FF8E2E3DD8885228CFC0867D8661D89D035B8D787CC943CBC72AD6E0AA1E215290757A79E3C46D1CA406868F088022F14C", + "v0_metadata_nonce": "A636A4C45168D316F30E5416", + "v1_metadata_nonce": "EF9A34E9881450F2E1CE9D69", + "v1_mic_extended_salt_aes_key": "20E1180F0D29E99EA3461791BCDA9C57", + "v1_mic_extended_salt_identity_token_hmac_key": "76967879840F98B5327C103B6E439BB538F0D219F61EF65C7140C8008ED69F10", + "v1_mic_extended_salt_mic_hmac_key": "7B8ACCDD365A02C8E2DC4D3DA7CCE6D9B7F5C4EBD65A6513DC9992B9CBD1BEAA", + "v1_mic_short_salt_aes_key": "531F84D2E14CC3266E44ECBD6D6DFD96", + "v1_mic_short_salt_identity_token_hmac_key": "03B61A2222358A41D08AFD8F242C1905994D315F544DBE92DE9243EA46F0CDEC", + "v1_mic_short_salt_mic_hmac_key": "362E7C04F2606012DE5DC59BB8DD1F3B5F5EFE66F6C9427FABD1E5C8F4D2F76A", + "v1_signature_identity_token_hmac_key": "C8F25EC50826357C319A9AE60C043945C9A8013FAC0E2F2C623E22977E9B76C3", + "v1_signature_section_aes_key": "E2BDA03CF3781A80500F8ECA73C1A84E" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "A7B3", + "expanded_salt": "D041484B84E924130D68F058E9FB45C6" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "BE6106BCD5D7388E53C26ECA", - "extended_signed_metadata_key_hmac_key": "0D98105D990B688F91C10BC27885E635B1DBDBF2DAE215EE49E04C06E33DAFEE", - "extended_signed_section_aes_key": "7A3A2341DB494F1D5AB346E54EA49729", - "extended_unsigned_metadata_key_hmac_key": "C6C0836CC438960704071E2EC71EC18219A7CA336E314C9DF1FD5F5848803C07", - "extended_unsigned_section_aes_key": "C00032E500DD04C16176DE5EF45466F9", - "extended_unsigned_section_mic_hmac_key": "2B813176336A7A645826F95F3763A536ED2EDC15EF25C87FAE32C3766114323F", - "key_seed": "BFF3192023AF42A5D4B3D12DC34350E7F41E214B25501A7FE0ADD19497A48276", - "legacy_ldt_key": "37E2DFCFDEFECB1FC486B6B26670AA37D3BE7E106E0C2CB5AFD9CCB1130EE7899A3D38CAF15142CD3A06DFC2A39D34503F7826EE517F9232DCC7CB1931855028", - "legacy_metadata_key_hmac_key": "5771D06F65AFD121908E4750EF2EBA0E9C385839E6987F30161FBCF88F49A974", - "legacy_metadata_nonce": "20448FEFB69E2643D7932CAA" + "v0_identity_token_hkdf": { + "expanded_key": "C3B32F82777B1C5EB860364BA7248ED1", + "v0_identity_token": "B809A4E6EFB05572D6474DBFF0E2" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "524B", - "expanded_salt": "F0B23D5EB99A02DF9E8A7D6F8B8A1A3D" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "BCC4", + "short_salt_nonce": "C5FBF8210A55A6176527E35A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "C6B9DB92F2818C6B57A3E386BD44B236", - "legacy_metadata_key": "A4C003398DEF995E0CF5457DF3A0" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "4F8C73FA3C662FC6516B4E7D3333B663", + "derived_salt_nonce": "01D90834B89356931A7C575478271A43", + "derived_salt_third_de": "DF71CC3039A2C9EBE8792C639573245B", + "section_extended_salt": "E667569C7C35342D78598CE967DDD6EF" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "EB8E676E9E53A4828200A25942EBA2CF", - "derived_salt_first_section_no_de": "A342A8CFFBD87DA2F95D1C72CB0EEA36", - "derived_salt_first_section_third_de": "6F049F5664239C49D76286B8218D64B1", - "section_salt": "8096BBCFC6AE0C6CA7A17D5623929518" + "key_seed_hkdf": { + "key_seed": "629137005F03D848FBC9A663FD4545698B82FC1A2A894DF9C41541A1B1B5B3D4", + "v0_identity_token_hmac_key": "46F120A4DF532721806D5D778D2C9E9178BD14D80F458D24001DCA4A22401CAC", + "v0_ldt_key": "07BF125D6472987365CF8DE0A31DAE3465F2005BED97016523AD98141CF4D4F68F6E5C193CE86F391474C6597827C371656D4339266E84202A174C5402C49386", + "v0_metadata_nonce": "ABF5B2E7D958BFF79882AEB8", + "v1_metadata_nonce": "86216A34350E9C1E045AD632", + "v1_mic_extended_salt_aes_key": "18B12EBCF7ECB1DFC20C7867D9B6207A", + "v1_mic_extended_salt_identity_token_hmac_key": "468A41138CBC76A60F8E1D472BB33152A67B9EDA3B7E79B9EADA3A3720FB3C8D", + "v1_mic_extended_salt_mic_hmac_key": "D980A878C750F1AE2C25A21C6045C8EECD81A0B45F400F10EEFB4222DCAE79BC", + "v1_mic_short_salt_aes_key": "EC807E84AF935FDCF6210EAFC261FC8F", + "v1_mic_short_salt_identity_token_hmac_key": "3683F211CF4FF6728E509372C732404FFD7A49EB6E2A9E011D8A2730A2766488", + "v1_mic_short_salt_mic_hmac_key": "ED63CB5202AEA05D6A666A9CF66AA76A0D10E6803A7F0A13C6303FC5D149B326", + "v1_signature_identity_token_hmac_key": "B1CB9EEB37699A13A225BDF36102A6E80610AA9A97B8A6B320E772FFDC6B5972", + "v1_signature_section_aes_key": "58C40319B83E496188B699111FB9A659" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "B8C1", + "expanded_salt": "1E42061F10934A6380306B3CE306CB35" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "586425C6E1CAAE439F588912", - "extended_signed_metadata_key_hmac_key": "FD0CA08040BB854BDF7414DA7ECF4733A094644B4FE3473C04F787DBEF6E53E1", - "extended_signed_section_aes_key": "E4FA3E811B0C7263CCE2CD60500587A4", - "extended_unsigned_metadata_key_hmac_key": "6E6DA7DC5B6F17C7B6C8B37E9B8E82D09DA5C4300DB8C601CDBB258161A8701C", - "extended_unsigned_section_aes_key": "3E0E93D5EA50FC6420B0331F2D30EE07", - "extended_unsigned_section_mic_hmac_key": "78F44EA95AED2D816672A0EB7BC16B8DA13DC285CC903E63BB844BF6499949D4", - "key_seed": "66E4BFB8633C10BDD7B8C2E5653E014BC1E652D809487B1810DBF79515ED66F9", - "legacy_ldt_key": "D53EDC7BDDEF9CD6FFA5C7DCE7FCFC6A4653412B7F690454201BB6536FCD2EB04A090D3C252375FD703D87869AF7F6CC60EB7F381896396662C472C5B1626A81", - "legacy_metadata_key_hmac_key": "466B32DC5CCF02949C092E5AA5AB321CA35E339CA8F6483FB1F9F6F0C7E6A438", - "legacy_metadata_nonce": "BFF9144266F9BC3527CB8C46" + "v0_identity_token_hkdf": { + "expanded_key": "5E342014C14C891E73C9AE86FD46D131", + "v0_identity_token": "AE279658E230EA4A84493249656C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "CCB6", - "expanded_salt": "0F9B6162C8CDBC3092573D85B26DBC37" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3780", + "short_salt_nonce": "1BEE1C6648B348133DCF4E1F" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "AEB39B7A005D27F8DA9FAB9AD80D220E", - "legacy_metadata_key": "A52FF0A8837236A5D3DDA03BA23E" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "E4EC66F0E365A49CAC1266A28F307798", + "derived_salt_nonce": "7478C715C11452249E821EA57A9832A4", + "derived_salt_third_de": "1A1F76CB9C0358FB86E217487B860855", + "section_extended_salt": "3E351E1A8DEEF7C30011566EF72CCF33" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "FC6812BA03F06BEFD59BF0F949D8F449", - "derived_salt_first_section_no_de": "2DCB709ACE9617A6119BD2CC960EED9E", - "derived_salt_first_section_third_de": "FE06376C4AE96023D51C6C8475072558", - "section_salt": "2F808BAF3FE99E6E84B565038CA90BC9" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "D8C89D6886078AF21EE678DB", - "extended_signed_metadata_key_hmac_key": "FCE0422748BD4D4082B66F25B06DD3056E9D37C135CF212CE1C8631FEA94F864", - "extended_signed_section_aes_key": "9EB35E1816D04630AECA453BC64A8FE8", - "extended_unsigned_metadata_key_hmac_key": "D161E19CB3638E925E028602B7928D6889C776062DF66A33C97F2C45890C0581", - "extended_unsigned_section_aes_key": "A7AB3B735821FB8F59F63A8E8DE3F3F8", - "extended_unsigned_section_mic_hmac_key": "CEAD2B2095603CC58A1C5DDE0A5ECBC2FC960840DE6A463E9893C97409B0437A", - "key_seed": "3538A99DC75533C5A301539C166BD8A6476AF6F5F52A73382441681781283A4B", - "legacy_ldt_key": "32360EC7E4FE0B3C5FE27E236639D62C5C81BEE8397B320688087B4D4009B10E6C15B6057CCE1BC1B8F8732606E730BA172746D8CBD34DEECF911CBFB9712B15", - "legacy_metadata_key_hmac_key": "90A819E29083F6DF7FD2C7E9EC4A872CF4887CA8D964984E49C4CCC292EB8938", - "legacy_metadata_nonce": "0982939640FCC0CEE8551409" + "key_seed": "AB3AA3128FFAD716B58E523B678189AA0FC39C9D84F627EBF5D1A742E6B35918", + "v0_identity_token_hmac_key": "C24032686F78556724A111E743306F7B583E9369B80AF08B1A680A04FF46B3D4", + "v0_ldt_key": "65DD7D59DBF3F853296D96F35BF0C350740D0223DD2629A952FCC2B5349B49A3D5E6D41EC120AFDA492F331FB573F122930A98F506B1F9E34AB7D1F38F6E9461", + "v0_metadata_nonce": "9432AAEA580486B80C2CEE67", + "v1_metadata_nonce": "9682BC001611E3C0271E96CC", + "v1_mic_extended_salt_aes_key": "AA2EC2476363A9127ADF96E354A3694B", + "v1_mic_extended_salt_identity_token_hmac_key": "05BE6AB4AD1FCC92C52883DB0FFD4369D472910C0E8417C551AB834962059472", + "v1_mic_extended_salt_mic_hmac_key": "378010DBE79B40985A0AEA35F7BDF9791E87ECEE34DB04D82084DEFA57ADB601", + "v1_mic_short_salt_aes_key": "15EAD484945F798DA57C65107009E5CA", + "v1_mic_short_salt_identity_token_hmac_key": "8B9F442893494B0D663B669AEEB2DB66D489B58FACDCFAE8D583019C16E72BEC", + "v1_mic_short_salt_mic_hmac_key": "B4EE0EBCBE390C849D864EFB7FBAEAC67932631186C729F76F3CA91BBC7680E9", + "v1_signature_identity_token_hmac_key": "A1673B9103B2253E455B8AAA8C2AE84DDD02BFEA7D69E68FE5D120E0B5E57B80", + "v1_signature_section_aes_key": "F7CABAA4EBF642DB0BCFA3C0C3EEA99B" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7975", - "expanded_salt": "AE096CF053C4F4A17ADB41DF4AF79D01" + "v0_adv_salt_hkdf": { + "adv_salt": "B20E", + "expanded_salt": "0E708DF23FF58C2D7F3F2D38017496BE" + }, + "v0_identity_token_hkdf": { + "expanded_key": "23472C27E2F659A4AB1A428AF3018C91", + "v0_identity_token": "9F3043710CA07FA18EB47719FEAF" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "1FEA", + "short_salt_nonce": "9DFE98ABABD5693077D90FFF" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "EA6B4A31500F98886521EBCEC6ECAAC5", - "legacy_metadata_key": "70A44BF295A6510C039A031BCB04" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "013B34285047C393204A70E0056B0308", + "derived_salt_nonce": "BF792D32CBA8F57028F7EB5BF225CB6F", + "derived_salt_third_de": "208228C6462B7671161768D2DE2FF375", + "section_extended_salt": "973ACE22CDA6F8F49B74ED9878CF3437" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "0818451F633193982BFEBBD61988FF62", - "derived_salt_first_section_no_de": "48ED1DF2C5BBF94DB0DADE30C0BE21C6", - "derived_salt_first_section_third_de": "633611AFE0697A6F36BC5B76E685391E", - "section_salt": "AAFCF56E0A0F6A8F76E2BC44E54F2B78" + "key_seed_hkdf": { + "key_seed": "96DC23CC175FA4AD9D019AD2697C766174387A431AAC413879F1E58A990EDF3F", + "v0_identity_token_hmac_key": "B816783CD9584B43744F9090F8190EFB73C065D80C55D42C5B0FB3E703BF3A3B", + "v0_ldt_key": "9A9E7488F70951A6BB0E9E73D4671A1B12B0C5EBB1A59D81258FE4FE80987B67AF2679B36873998CD5236433AA9FB12EFC52E66BC013B86583255FBD10C5C7D2", + "v0_metadata_nonce": "1ABAE096CF985C4732EE035D", + "v1_metadata_nonce": "7E7DB680E724225C9D1F1C26", + "v1_mic_extended_salt_aes_key": "A8C561D529E333D9B72002E0BEE43630", + "v1_mic_extended_salt_identity_token_hmac_key": "F45A244E0C64DF9AFF0CDACC2871DA35EE197C565CB47314A2158E944E0DBFAA", + "v1_mic_extended_salt_mic_hmac_key": "43950758403417002A184DDBC4991FFC5F0B2BC9CC8D2302784D6B59163546BF", + "v1_mic_short_salt_aes_key": "DC18AEDB7EF362A00A8A050D44860877", + "v1_mic_short_salt_identity_token_hmac_key": "CFB49BD705D54AC75EC449E1BC2D84B405FA970C728BCB004884DB70AB4E9C0D", + "v1_mic_short_salt_mic_hmac_key": "2D9C3E637E1E387EDDD22E586AC029A5FE0FE380502E1F9B1070869806EDA0F9", + "v1_signature_identity_token_hmac_key": "D8AC46D57D8F97D333705D9E37582923CC64EB9269692E044CB6F42B6EC7A1D3", + "v1_signature_section_aes_key": "3408666AFBFBA0F7C6B1956FF696A7BE" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "697D", + "expanded_salt": "87DD6D19A23B02C55F35861FD900852E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "30696C2FFD88091165B93256", - "extended_signed_metadata_key_hmac_key": "346B7958CA1259BB7197FDCA84B718A41AF9049D2DE6B472B64B19102D4240CF", - "extended_signed_section_aes_key": "854ADA9753D9A82E94E5D6ADBB22873E", - "extended_unsigned_metadata_key_hmac_key": "29D905607B3ABF4E2CD261EE4E67C19EF36F41311A61CAADB60C95FC468FB72D", - "extended_unsigned_section_aes_key": "DD5329454006EC3BD37FE3520810CD98", - "extended_unsigned_section_mic_hmac_key": "E4077D45CDDD895F5577A11D2FE9CB3BE65242D5DFEDAC87471C76038605741C", - "key_seed": "3719ACB4884750708757D20A58648804B8B7A614C176AEF7DFA6E0A5BB9CD5A0", - "legacy_ldt_key": "88CAEB0E79177042908D16AF2ED4025D95448A76E901A4B6195F405E5210A6889324B3DB121508D411A012499EDAEFF35A280BFCD32B35B2DC773AAFFAC9DC35", - "legacy_metadata_key_hmac_key": "A358646C1D338EC123E72FBCAF4BF615844764F91F8F2BD9811CDFCEF5FC2548", - "legacy_metadata_nonce": "EB2B57119D7662AFA40BC448" + "v0_identity_token_hkdf": { + "expanded_key": "B893C7D62C8D5D6C4D27F2F2E89A9388", + "v0_identity_token": "1173E9D7D4E23D4FA3AE5FED5C4B" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7BC6", - "expanded_salt": "F81E9EC1C91B1007FF2A32D72FB6483C" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8D74", + "short_salt_nonce": "A07118DCA162260AE3431760" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "36BB3E66C0820FC418EB2F1B873BDDA5", - "legacy_metadata_key": "89981C312BA536E82EC3B1090CA5" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "E64BA2437291F00276F06A9686145AA7", + "derived_salt_nonce": "0CAC865313B2A15A5080ADFB9217E5C8", + "derived_salt_third_de": "6FD2414155FFA0177A9F6417B607C3FD", + "section_extended_salt": "AC9AD659EA00A4265C647D5B46D4EB70" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "218AB6D163ADEB31634B1DED52E56326", - "derived_salt_first_section_no_de": "0F4F42636DBC8ADE1DF3383E6E8C80F1", - "derived_salt_first_section_third_de": "B667CEF8B176732FD56AFE83BFAA7611", - "section_salt": "D884E95FCD3A29F4E951A3C64D43C020" + "key_seed_hkdf": { + "key_seed": "1658D40CA1FAC8A4C15A8EE96A25434C631C2E3D2D710C74DBEDFF18D12C08A7", + "v0_identity_token_hmac_key": "396915CF17C3C5A9369928620FC934DF1A64641D9C46449026D74E47E3AF559B", + "v0_ldt_key": "6214EFCAA3542FEA0E81A3A5BFBF077E1CF90222DAB3DA4826218DDF8A41A28A2F09C2D2F75E50C24C0DD402BDB343D4B647A94819D3455A69D5B613EE36B90E", + "v0_metadata_nonce": "0DAB2F8A9B3C8741A7B7B27C", + "v1_metadata_nonce": "C22D7E7354F6A505678AA3B7", + "v1_mic_extended_salt_aes_key": "C6A465F79147E737D969FC5873DBF96B", + "v1_mic_extended_salt_identity_token_hmac_key": "32379AE42B10574F8D7934F0D75E7CB0EC82A6C7E5F626BD8DE737C3F8964F8A", + "v1_mic_extended_salt_mic_hmac_key": "9B25D3914B0CDDBDF5B73F2F95BEDBCFAAE65289D6649696D91C0BCC8926B619", + "v1_mic_short_salt_aes_key": "39C321D60F6E9871C6F0E5F08021894B", + "v1_mic_short_salt_identity_token_hmac_key": "67F7D65051D4339DCFD118B55233214FDF6A4D22104C123490267C0A68029A37", + "v1_mic_short_salt_mic_hmac_key": "97B7E56E79C9F0E05ADE70F6E85B0104B08150A1BB253451FEE37A02AB2F607E", + "v1_signature_identity_token_hmac_key": "019A2FF53B587F6B45139C744973D4BE7F6BAD418625181AC3F0404CE042F125", + "v1_signature_section_aes_key": "FBAF3E389EB39C82A87E36BF26459FEE" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "C489", + "expanded_salt": "830448B54A2F8FE3CF891DC67A61FE6C" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "497081ADD0EAAD948AC3D743", - "extended_signed_metadata_key_hmac_key": "4CF4E05DA1B0EF538CA84515202E1AFC845E94A236C672F091D7998A1AFD0D24", - "extended_signed_section_aes_key": "7DF8CEF6BFDA7D1944BC5F5105BD003D", - "extended_unsigned_metadata_key_hmac_key": "4892A9FD8A1080F06D299D8DF2FBD1382E5F31E32FDE1B974ED1958AD7348C08", - "extended_unsigned_section_aes_key": "608194400C0D4390A12891645FEE4EA1", - "extended_unsigned_section_mic_hmac_key": "8B3B932C61B0B9E2FF883B13791EAF9EBBE382E4539242DEEFAF03C6930FEE9C", - "key_seed": "871B0FD2D15F8C5EA49B610C544D0F957884876C614228083A414F8A441A2D30", - "legacy_ldt_key": "D41A6CF8C5BB99BB8FE8B33F341FAD33AF603E980B6C2FF70B6F0BC0080F655141D0421932F573706664085752947678D4F106E1FA71E8E584445BCE7ABBA35D", - "legacy_metadata_key_hmac_key": "99D2C4B908B8FF9151F30A4B7ADD9590BF85EBD4D086560B32A20AFB529CC524", - "legacy_metadata_nonce": "60B88352445ED074EA447690" + "v0_identity_token_hkdf": { + "expanded_key": "C97A235E30AD867BD583C5465BAE98C6", + "v0_identity_token": "C9F646361843A0AA277C1786D452" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "BFDF", - "expanded_salt": "AFDBB3A928B41B9C72F3CC9C21437B63" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0043", + "short_salt_nonce": "5E4D5C6D9A148F2E2695D39F" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "4F832379A70733EB481C98C287573D51", - "legacy_metadata_key": "9C8893A6DB94328439157550279E" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "EC8C3C7B3A563015AD914D065F065C42", + "derived_salt_nonce": "40842C94F4F5046882D39A1F353F5174", + "derived_salt_third_de": "CF99D9895D39ED5AEB35E4596C63B4FE", + "section_extended_salt": "FC4A1004C457DF7D85788332C3ABF9FE" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "1F3AC1292A3E34943F65ACBD5A5D5F71", - "derived_salt_first_section_no_de": "6162875F35A6B9B20C0F81C8CC9BC0D6", - "derived_salt_first_section_third_de": "EF5A3849BB1526EFEF254214AE714CD9", - "section_salt": "4058BBC28C1E874801AB570EAA0B1EB6" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "213546D6654AD76E62DDABF6", - "extended_signed_metadata_key_hmac_key": "359FCC4FB2576B773E11B61937E190FD0D9249EFE348AAABF18EEB331373BF66", - "extended_signed_section_aes_key": "48FEA76F4BA226E1880B3D8245125AEE", - "extended_unsigned_metadata_key_hmac_key": "59118D794BC59C9D1F4A6008E3AFB9FDBBC9F874C1F6C25812ADB75AD7744314", - "extended_unsigned_section_aes_key": "F55C149FB252D0744AAC781C04E87251", - "extended_unsigned_section_mic_hmac_key": "6A6C6DD45298CE923C01E0CCE68519E1C6E2C494F0E9476E596539DCB30423FA", - "key_seed": "7B65E45190EA159343E5562D63AE83ECF4B15DA7506706FBFAE25DC607D88720", - "legacy_ldt_key": "7801EA9A9FE16C5554116B72463EF63DE1565CA8AAF6DC1025FE6AF53C4B798AB15609774385FC25FDDDC4D28E57A2661ABDD074638A10C7C9CD7E852CCBB9A8", - "legacy_metadata_key_hmac_key": "3787DCAE0CC30E049935477D8562D380B9DB021BA494FD1ADD9925DBC8864A85", - "legacy_metadata_nonce": "902CCFD130ACF873A78F9481" + "key_seed": "8F5CACEFF8E195DC29A6418D15E42C22D93BC3893EC740FBE9DF3BC36A6E87C5", + "v0_identity_token_hmac_key": "B74E9A4B1A1967E5F37362FA6109362D3A93F2EB4D4488D938EBEAA0519B82F7", + "v0_ldt_key": "2961475C355C92A682E1AD7A0B545BA5F91B8D1C97396C77DFFE2CEFB7DFC564A8816469472B28611021D03424545C54FD68C87BB3513EB5B1E7B96614965D25", + "v0_metadata_nonce": "060B128C71924E5F35403978", + "v1_metadata_nonce": "0CAC86A9E31724738CB16769", + "v1_mic_extended_salt_aes_key": "A16666440709AF7D91C3FC11C0F40BF5", + "v1_mic_extended_salt_identity_token_hmac_key": "B54A57DC9F832214FB383DA4123ED089B16C28480D4097DC57F108272C0E53E4", + "v1_mic_extended_salt_mic_hmac_key": "73766408361E3A670635EEB7C9FF70A72116819F94576737C06FE78910063502", + "v1_mic_short_salt_aes_key": "0C8A3C2D081449F4F263E11730F59385", + "v1_mic_short_salt_identity_token_hmac_key": "E46EEBE36262EF589672F67E20DBBE24DC18B863DDF4CF9D8330DCFA3CFAA3B2", + "v1_mic_short_salt_mic_hmac_key": "5CE78E09F37386D4554DFC39B22E4AAF28F812D335BD372583B7C3F1A1552B9C", + "v1_signature_identity_token_hmac_key": "B947D986D221E4C06CF27FD3352674D5DE51FF5B14885E36074D363B286B28F1", + "v1_signature_section_aes_key": "49A0920DE44EA33D0E2FDD6217492837" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "9A70", - "expanded_salt": "4ECBEE3BBC2B85F39E379254D7163227" + "v0_adv_salt_hkdf": { + "adv_salt": "28F7", + "expanded_salt": "6CF0800012002D2E48A3A5A8AC857378" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "AD4B09305929D4A277BBB2D3227B54BF", - "legacy_metadata_key": "ACA208D4C92030B19114C73F8399" + "v0_identity_token_hkdf": { + "expanded_key": "A0BE87B5DEAEC03D93A1BC9C10DD28AA", + "v0_identity_token": "412DACDC38349059C26766C5F8AA" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "29B9", + "short_salt_nonce": "17F243E45941156F9CB40E66" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "A2D63A55BABCFB0F636B0D3621C4CF0E", + "derived_salt_nonce": "7DA7DEB96787A854B3B02CD1D3D90BBC", + "derived_salt_third_de": "4A653154FF6C376DD0EB5CE64FEA70A1", + "section_extended_salt": "8B2303C4EE99348E3B5B34EAF99E29E6" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "34BCFCB74C32AAE99B97D24A839C4533", - "derived_salt_first_section_no_de": "C6C751B4257933CCE05AD7C336B3F17B", - "derived_salt_first_section_third_de": "292892273B46FB6C99FA4BC3C44708BD", - "section_salt": "74F5AC8F69F601C07AB4AC92E9F51C3F" + "key_seed_hkdf": { + "key_seed": "CB59F22A81FE55D0C5BC1B5D22D4212A811CD1138477D21FEBE17C5E217C87A5", + "v0_identity_token_hmac_key": "3BE67C6ED8D821E5C74A7E68A7C5B570362975613E1F974DB855546D0151E3D6", + "v0_ldt_key": "9F6C8A4BCB91447656C00ECAEFF72A01A2EA4B66450A3F70B0D1FBBFE70ADCCB4F69D8DF956F44CA877515D21ECADCDB425DFEBF5A3D7025F1D7603E05750A29", + "v0_metadata_nonce": "D7E7D92A0A0A19575DAAFB88", + "v1_metadata_nonce": "B51766263DA243F02A43D0D5", + "v1_mic_extended_salt_aes_key": "37DE33735A25248A6557BF1A68031161", + "v1_mic_extended_salt_identity_token_hmac_key": "1AF94FDE53770179094074B778B0F0F9C4F093C33FBE149C6D597CB20762B36E", + "v1_mic_extended_salt_mic_hmac_key": "CAB44B647CEF4A189CF3B89428DFCF4D8D7EF74AA05252D4E2D1473472B17E29", + "v1_mic_short_salt_aes_key": "480B8E97EC00901A06850E0746BADF25", + "v1_mic_short_salt_identity_token_hmac_key": "6CDF2DF6C49DDB32051C172679F731F040549742B92758445712E5380DB052EE", + "v1_mic_short_salt_mic_hmac_key": "751622D2D36222D292DB1FA835FAC4676610C27FE961AC28B6F19EDE4FE6D233", + "v1_signature_identity_token_hmac_key": "DB49365A1148EFA93B856ADE848B15DC81143FFED26E29811ED4B400D3C3D880", + "v1_signature_section_aes_key": "8376773D764F42C0C02209207DE4AE80" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "3564E475886853F7BF5EC55A", - "extended_signed_metadata_key_hmac_key": "35A5FF3F932BDC655A9FD8AAEA36E25ED917C509A42F3337E3E3E89F2DDBCD0D", - "extended_signed_section_aes_key": "470C528EF53B704C515C58A17EDF6C86", - "extended_unsigned_metadata_key_hmac_key": "4144AFA9B5D527A9D1E05AA282A7C1D00DF51E79CFE93D7578043A5191C8D1A7", - "extended_unsigned_section_aes_key": "C32F8F9706900F0FCFEE149D120CAAB5", - "extended_unsigned_section_mic_hmac_key": "7D1D483580DA73C3322F088E3D2A24FE640A9F818CBD72842D288364A1937286", - "key_seed": "A8590C79753059E9873CB4F0BEEECD1B43071D76BDD4A1E07809FFA0B89AD5E6", - "legacy_ldt_key": "82D25B8271ABE1D6262F09DA005D99BB6046EC6BB387800B4E2E01993998867FBBD487C65E0BCDCECBDD89E1EA23ACDE697862E2D9B644963625BE8BAC4E3F99", - "legacy_metadata_key_hmac_key": "C574697B87A56EA447BD202BFD3D960E2393119A5AA4BD270CEB0E37B719BF16", - "legacy_metadata_nonce": "1CFD6A666E8F405C39D9E1AA" + "v0_adv_salt_hkdf": { + "adv_salt": "FF69", + "expanded_salt": "C45C95D99B373A3ACE8CD7D1889F0013" + }, + "v0_identity_token_hkdf": { + "expanded_key": "47F9BAB879C0FA2AA98428A7FDDC7463", + "v0_identity_token": "CD1F7F15A691D8D7C30C42CAF69C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5685", - "expanded_salt": "8AF7ACB0C156A5882E64105535A8521F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "C115", + "short_salt_nonce": "78A4DF6F4645BF6868D3B8C0" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "9B9FEE02950DC453BFB4EF3C1CCF4811", - "legacy_metadata_key": "B2C2A05B519CF20021C9996DF808" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "557438A8D86570CB0179CC69F8B1653F", + "derived_salt_nonce": "4BB982A676DCF6715DBA55A5DA00D25A", + "derived_salt_third_de": "F250FD05CF2307636F60750CE5E9B323", + "section_extended_salt": "941E0C341EB666240EDAAD47239DABD6" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "89CF340356F2E40A23A033F98DDF7D28", - "derived_salt_first_section_no_de": "853D5F3E410E67A666A9E41F86BD4EFD", - "derived_salt_first_section_third_de": "DE0B861151059E218B754C32B123C147", - "section_salt": "226836AA61CC797529A81307D64EA301" + "key_seed_hkdf": { + "key_seed": "ED908C5A4DCEE6429570F2DF17607E087EAD24F213D1A11EBBE62128AD2CBE07", + "v0_identity_token_hmac_key": "6C7B5EBBDD2DA8F1C411A367D3049C91B8C3B1CA6BEE58BD5979CC4A7AD3CC55", + "v0_ldt_key": "AF41A2C1CF19A7036CBDD5BE73C1F4C6D035A3FD205588931348B680B8826EE4A9915E6697DB8F4EDE0751DD746CD52A4A1A3C682B515A736F8407717A0F8ECA", + "v0_metadata_nonce": "AC353D32F3A9AA176DDA755C", + "v1_metadata_nonce": "F5D1D9471B14EA7BF02C3E61", + "v1_mic_extended_salt_aes_key": "9094F93C7C363EC83C62938E55F34A45", + "v1_mic_extended_salt_identity_token_hmac_key": "CBC3A7ED9BD82335329FC83EAEBC6C57A17D41A94C9E57F5C53EAFA29E3E6FBB", + "v1_mic_extended_salt_mic_hmac_key": "C8C2EBA26F834A9E3C96C2B7E4F697D1A180FC8F854A6169710120DB29BF0C0F", + "v1_mic_short_salt_aes_key": "CA6577851C9BC850A88F485732FB4C52", + "v1_mic_short_salt_identity_token_hmac_key": "EB2B6628523226BE853EC1A2A23C8B8F210B1C4B40EDA72435F65BFEE3AA066D", + "v1_mic_short_salt_mic_hmac_key": "D17C34BC36306CB1AEC52A7125B0E7D6C9A50F4B9DAC6015BBB9D6E933E7A2DF", + "v1_signature_identity_token_hmac_key": "1527905BF57561A93D2EE2509172BFB08BEB8D1456D17B0227C3EC621766B850", + "v1_signature_section_aes_key": "4EACAFCBAEC4739EC7726C78BC27BEA1" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "285561F74E853C3208B51748", - "extended_signed_metadata_key_hmac_key": "32C03F14E9AA9082E4A87375B53543103A6B8B041922778BFA9C083D5E1F39B2", - "extended_signed_section_aes_key": "A0BE8DF66519E26A80CA4C1D84958150", - "extended_unsigned_metadata_key_hmac_key": "98CB9A09F93AB43D229C1D1699E998BB21DCC535128B4F3EBA93939CB2806199", - "extended_unsigned_section_aes_key": "C579BE805B3801B4680EC72CF6F4C888", - "extended_unsigned_section_mic_hmac_key": "DAE01D0E3D8A08A8B3BB00A48BC81E8C6B730133EC90A03326189F2E43A1B0A2", - "key_seed": "82B0C4B354909A4A05C43CFD728804FD58C9A339362576865378D1B92A3DC3FF", - "legacy_ldt_key": "A939DFBDC50FBF27637C0B2AE4357D4403A5E3956373BD17CB8C589657517E79D1EB900F634E3F41092E4E25787C6161D2D18EE09A13A35A354A449AB8292BCC", - "legacy_metadata_key_hmac_key": "4D32558AF034F2AC2E63AB36256B842852598D49ADC8E2F244C8AC13DA1E9D04", - "legacy_metadata_nonce": "F00120FCD5FFEC079D2CA173" + "v0_adv_salt_hkdf": { + "adv_salt": "581F", + "expanded_salt": "A5DD61D8ECA1EBCE4C322C8E080C9AE8" + }, + "v0_identity_token_hkdf": { + "expanded_key": "8EEA2717A9052AFE66226349118182DA", + "v0_identity_token": "9675B523AB5F81A7ABF9903D9C7D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "6C58", - "expanded_salt": "92EC631F08ABD78DC8552A2484D568F2" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "BA45", + "short_salt_nonce": "BDAD50E1174C4F1A4011335B" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "04443FC782143B5B62BFFB6F4E0EFE8C", - "legacy_metadata_key": "F011C17EDC3FB4095C9ED4BFCEF6" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "C92C5055A19F1B8A0FD1F07705B454DA", + "derived_salt_nonce": "C2603BFA63695C6D3CF9F8C294217640", + "derived_salt_third_de": "C3509C601D0F373B0875B6B1F7FC7D9D", + "section_extended_salt": "782DBF528A022F527A00408A045CEDE2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "7104EDAF3D39ACA85F0DE66FB8A0E6A4", - "derived_salt_first_section_no_de": "297FC2DCC22C9793610FD3504DBAAA3B", - "derived_salt_first_section_third_de": "CF455558C8C67E5AB573C79AC356B02D", - "section_salt": "19421ECBB444B94A369F1684DA6E87F6" + "key_seed_hkdf": { + "key_seed": "3F7B6F2BBEA10535F2EB1830A466A58D1976838B2F56929C5632DB1D35DB9FA5", + "v0_identity_token_hmac_key": "84CAA04B2BEACAC2481CB59E58F2F8D2750130791DB02F906ABBE8AA778F8DF1", + "v0_ldt_key": "EFBA37A2FD32D2AD2C89489B2ADD958DC689B71CB85FDC132708BEAA5E450FD34F585CF0C40386715ECC9B1F334EABB5C6E9D071A0FD98DD752170F898DB0DCC", + "v0_metadata_nonce": "FAAAE5DFA198AF0DB586D4F0", + "v1_metadata_nonce": "1200358F9DF02A61AD1B3720", + "v1_mic_extended_salt_aes_key": "444C1136B55AFB20194F8485CDBAB199", + "v1_mic_extended_salt_identity_token_hmac_key": "DADAC9D5D6272025A43765625864D677B563A0EC550ACBF1D42D1F1C89C3ACF4", + "v1_mic_extended_salt_mic_hmac_key": "15F1121625072AE546BE7E9A17CAF4C7D85F084CB0BEA894495F1CC37E97E60F", + "v1_mic_short_salt_aes_key": "6452C325F1DF8A9E0D4B6D4D9EA59A7C", + "v1_mic_short_salt_identity_token_hmac_key": "4397BF6738AC22CFF3C4272C046F488139107476E2566FE66C789E240A624803", + "v1_mic_short_salt_mic_hmac_key": "A7FD1087175D5FD000D3FB744CA35120E232C54DC167B776F42B9EB5A8453079", + "v1_signature_identity_token_hmac_key": "368BFF1160B108CE21133C215812D25D36FF6669B72C4B88BACA2D31A597C8A7", + "v1_signature_section_aes_key": "351F043D8B6435E5E73684B10F79471B" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "DE49", + "expanded_salt": "FECD5D5E1E04B1C52AE646C5D47B1B26" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "C1BCED6F35A78F0FB40F698B", - "extended_signed_metadata_key_hmac_key": "30BB3C9AA11570317B0551F667CAB16554C72400B318F99E70FCDBE24138CBB9", - "extended_signed_section_aes_key": "A32C24E09D4ADAAE24CA1944697B961A", - "extended_unsigned_metadata_key_hmac_key": "4B5F583F19BB6D221E6105E55B45F9A2CEA17CCE179B03BEB99A9C50147CD2FD", - "extended_unsigned_section_aes_key": "5F97AE24166CBFAF9BFE96EC213142C9", - "extended_unsigned_section_mic_hmac_key": "C7AE5C3B45B8FA9AD2EB92D39CCF3D67C9F10BCFB44BDC747EEFF84FDEAFF921", - "key_seed": "ADBFB02FB9DFC75BD74516C628285096F2C4350DEA65D4616BB4DD30DF2C8907", - "legacy_ldt_key": "9CD5AFBB5CDB94FBF0A51B07C7B8C0CDE7EC9E8985D40CCB6E2EA21EBBA409B9D5E2123BA5EFB45000FB0660EC063274F4E112324037D7548F4CC9DD2B00A9EC", - "legacy_metadata_key_hmac_key": "CE65891EF8F79F286A62705AAB9FFDB3CC49FDDC42F084BC06D11A4B7C254403", - "legacy_metadata_nonce": "5630BBB459F3C2FF04480607" + "v0_identity_token_hkdf": { + "expanded_key": "573FB84EA56E4DF16BB17C0281D245AD", + "v0_identity_token": "EFD9C7521556995E1E091848A8B0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "6716", - "expanded_salt": "7EC07D3176C5ABCB3731A38D7CACE699" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3FC4", + "short_salt_nonce": "68CB8DB099FC125FE4E2AAC3" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "97CCAE1E7A2BB5319834306D940B4798", - "legacy_metadata_key": "736A5584FB8EF29D722171B0E133" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "9DDDB28462DBFCA74F63FC476FFE3D46", + "derived_salt_nonce": "85989FA93A8C9A85A7DA598529479045", + "derived_salt_third_de": "FF1A21F20BCB2A86AFF9A29CB42A3C46", + "section_extended_salt": "FA9DB8C9A1376BA0265420D4B0588C21" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "AD388BD4C9CA419A983A50DE70B96E87", - "derived_salt_first_section_no_de": "ABACFA97695D2FBA00E7D5F2BB322165", - "derived_salt_first_section_third_de": "C3BDDC19E7A1D453F8BE2B85958C2B6A", - "section_salt": "522FF617F4877D7FCCB569597903DD05" + "key_seed_hkdf": { + "key_seed": "E21B543EBF98DEE5174CD576F4F719ECDBF30F15BF7635A11749DD647EAB06C0", + "v0_identity_token_hmac_key": "6889E19D6A9AEEFA4E19A699E0FC8A813B709CE5BBA105C8FD6C6100833F8985", + "v0_ldt_key": "2EF57271E0BD7D977086265C78C8D0A529D5E70A3855DC650EBF338DF0F914394CF7DC5368B46E8F8E921D9D69A00BC04B2ADC01CBA954190669D1D4DD3B4C03", + "v0_metadata_nonce": "9D1D2B472358E5E253B9A79C", + "v1_metadata_nonce": "6F6E74240EC260B896F73EED", + "v1_mic_extended_salt_aes_key": "10A906B13EFDF85CA05741262EDAD70B", + "v1_mic_extended_salt_identity_token_hmac_key": "B77608559C639713B7E58B631DA3706B1D1E90F95871D4CDAC3F65436195946D", + "v1_mic_extended_salt_mic_hmac_key": "3A3BDEEC0AC9D04A2EC9E03D8B32BB48BF7EFACEBC4D946D8FF6B814D5661234", + "v1_mic_short_salt_aes_key": "6914FF089524DD20681F6A250A3C2BC0", + "v1_mic_short_salt_identity_token_hmac_key": "0B75CD46D539DECA8A7D14F4F7ECF2F1A2618FE449722CECC2816B5D674EACB2", + "v1_mic_short_salt_mic_hmac_key": "19D33DE899A50CE211E3BA3727669A6470EE3F52B17AC200E5FCD6FDFD000D5B", + "v1_signature_identity_token_hmac_key": "324954DBD6C28C2DB4C1918C3C1964FADFCD0DC2CD5F3E1F8EF870DE57059F5A", + "v1_signature_section_aes_key": "78F98654143E5EA976DC7EF3080C4E99" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "42AC", + "expanded_salt": "1D31BB4D6407E99C1009B34ECA9488B8" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "2D02434C5257433FC62E157D", - "extended_signed_metadata_key_hmac_key": "BC06E2ECDF44C4E749F07AA9FFDAE6786156382DEB38214C23ADF9676273F058", - "extended_signed_section_aes_key": "277CC3A4FBD6FA8A0433813C35AE03E0", - "extended_unsigned_metadata_key_hmac_key": "A93DCADBFDB56157B57CE0FB27845AB3B14072BB8F51AD430251D5FE431E4862", - "extended_unsigned_section_aes_key": "01AACC054CCC1E4C69A30F5BDB083DF6", - "extended_unsigned_section_mic_hmac_key": "ABD3E647D57721A8AFD6CE354E65FA9717FE273B3D3002C9EF116E3060EE49CA", - "key_seed": "04A09B2901EA8F73BF4503081DA2B2F1C701C8FB2E6D0727229AAF18E618D6B2", - "legacy_ldt_key": "F728279808DAA6957480F08D9A71EAFCDCA22F6D8BB646A1B55174997DF3C161D95E50BDC84F2AF897D97319D86D6CF1F4D29755B2A4BD4C896188B493579F69", - "legacy_metadata_key_hmac_key": "93F7B7662855DC419AEA47D99180AABAA42DE340259E5875C60E90DF9600F419", - "legacy_metadata_nonce": "D451E840855973EBCD5CB21E" + "v0_identity_token_hkdf": { + "expanded_key": "96D5FFEA8F177301FB6C714E41DC89CF", + "v0_identity_token": "66F176D3B94C02ECD0D4FFB70273" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "4BE1", - "expanded_salt": "76209392CCAC5FB22D8EEAFAEDD20ECC" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3884", + "short_salt_nonce": "6C06CC0653B5BFD0AF6DEEC2" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "2EAFE79FB0028DEEAAABCC1ACE7F7B08", - "legacy_metadata_key": "1B9CE163FB544E4B189C5F2B72E1" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F7684DEFAC951359A02D3C3478964CA4", + "derived_salt_nonce": "89DD24B2821B57501E07BF8913BA5B23", + "derived_salt_third_de": "381D3B6413BE8703AFFB0D17B38D372B", + "section_extended_salt": "58A07B28332F5BEE07B5B2B6501DE060" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "2F0D5E19F15AD52B54C40021FEE0F9E1", - "derived_salt_first_section_no_de": "7826CEB8C46C4FE75DFAEB56973BC3BD", - "derived_salt_first_section_third_de": "CAC8343515178DAE36FD923FEBD8452D", - "section_salt": "CDBB37DFF788530779D089D6EDD732F5" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "71177ECD2A4AF37C9608B3A8", - "extended_signed_metadata_key_hmac_key": "B1ABA8C85AFC6DF1FA37250E164F40BD88ACBEA2E74A12437E13C3E0640C1FD6", - "extended_signed_section_aes_key": "FD479476C02CE97482D3AC90876BBD75", - "extended_unsigned_metadata_key_hmac_key": "01D6F430855496FE82A98334CEBD234A31BEBEFC900AEBE86C89ADDA184F1510", - "extended_unsigned_section_aes_key": "7B66F349E92928431F7499B1609BD60B", - "extended_unsigned_section_mic_hmac_key": "AB9676BE62D30988CB70A5A7F958E73B2DB6765CB2B06F06F37D462A930FCE4C", - "key_seed": "7C6A118C1331C9276169A367E049962899C7A2E20444F9F964D83FEE4B0C46A8", - "legacy_ldt_key": "A0C190B05BC945FE38E1C117D1AB06FE7DA9C46D74F76974CFD558344964054B05EE748E0F8F17D6A3AD995B129EC83F5A803F9FDE0098551020356E59CBE674", - "legacy_metadata_key_hmac_key": "C12FF27071B70A96145919151789D0C4311B5CE896C010D49431A78FF933393A", - "legacy_metadata_nonce": "F388B3284F9C4983BAC29498" + "key_seed": "37FDF4CA1BB248C94ED307E5E1764EC0165EA1E981CDC24D6EB13DAC7605CF9F", + "v0_identity_token_hmac_key": "07BE3BF8E93F634BCC23B83B7B417DDCB274E250306265BF7FC4A968273B5FEB", + "v0_ldt_key": "60FFD2A67E1C4ADCE2D76A3DC22C0C019DE651E563B3DB348BC297BCBA807FC85647F2769B793C77DCE750B36B20070A8C3F9AD83B5A2387C4EB56A9E3FAA6B0", + "v0_metadata_nonce": "29107E6A280BFBEAEA342EE9", + "v1_metadata_nonce": "FF7F2C8E68DE7F6D85C495AB", + "v1_mic_extended_salt_aes_key": "8B784FB1DED40B601E99C37E0D5AF873", + "v1_mic_extended_salt_identity_token_hmac_key": "DB2CAF59508F29C763E7C9474B976D98146DE1A82043081750B96E64D8D54DD7", + "v1_mic_extended_salt_mic_hmac_key": "FAD94CC0F43729C896A4B38B6FC314A30A6235336FB9144857F74DBA62446C43", + "v1_mic_short_salt_aes_key": "DA65AAFCBBF298770D7E4C20E8ED4015", + "v1_mic_short_salt_identity_token_hmac_key": "A67A0798A0395495824110A9ADE3520DC3E80110046C46C31AE59B133A31D8AD", + "v1_mic_short_salt_mic_hmac_key": "A2BDDA2BF237949C6F6C25D8A5138966D2E2778FDA5692C61CC8DD0B5CE06CCF", + "v1_signature_identity_token_hmac_key": "E046453AB6F68FEDB7A960170A2827B28037DDC8DA1E7F73D3CC8C83A15EE813", + "v1_signature_section_aes_key": "445F1E3B3AA663DDEFE1E5C0F2AB972C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "B1F7", - "expanded_salt": "7DD107544AA52412D36D5AC0C65E8A86" + "v0_adv_salt_hkdf": { + "adv_salt": "9EA1", + "expanded_salt": "5A3B5015E1D58841D0A30728A25F4604" + }, + "v0_identity_token_hkdf": { + "expanded_key": "830783B4EC92685F1E440371840B7E1B", + "v0_identity_token": "AB8F48A84D5F7B02FCA0E0D197C9" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "AAC4", + "short_salt_nonce": "BAB0729453AC44CB60695F7A" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "B6A84A4591AA5C4115D0D47E9D475DD1", - "legacy_metadata_key": "66D7DAC60B00990F01D618D929E7" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "FF510969FFE54C346C277BCD12314A23", + "derived_salt_nonce": "C858D33D065BE6BE321F09A182E4E0B5", + "derived_salt_third_de": "8C972C1345CF4B88552917A6C0AA0132", + "section_extended_salt": "947F9A9E1AAC92228E70B97E686092B2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C03F4007F1E7180EC871FE12519F98B2", - "derived_salt_first_section_no_de": "A76C0BBEFDC804F829DEF65EA3F51C90", - "derived_salt_first_section_third_de": "A4DF26763162B19617B24D357C4E7EC3", - "section_salt": "4D555178782275479BAEBFCD147C9C61" + "key_seed_hkdf": { + "key_seed": "BF78AE44C8BFD059E8A47A00B4678650360D0BFDD8D58821722ABC1B78FA6E5C", + "v0_identity_token_hmac_key": "E185FF7397CBB44FA99048A46EBB22C624BC1E3A21F2ECEDED91686440919752", + "v0_ldt_key": "6FF4D69DC4CC5D5CF17589ED7EA6FF8843D4785FB5AAF89B8989E5C9EADF8B915CF0F2A2974240C8A7C49B571986E4BFC93F3B9F9D809A69FD89DA0C470E91E6", + "v0_metadata_nonce": "F25EBDA155405BEA86941F45", + "v1_metadata_nonce": "7787AB19C65497386A035A57", + "v1_mic_extended_salt_aes_key": "68A1F6E9E2E703728795CF51AB018597", + "v1_mic_extended_salt_identity_token_hmac_key": "A93B60B9DB23C48E2128EE8A0C982FE2256BAFE463F51C99E1FF0D6A5036EAF3", + "v1_mic_extended_salt_mic_hmac_key": "BF3E481EEB971717B448D4EDB765F2C9291C3165A8C021742E3B33D84474772C", + "v1_mic_short_salt_aes_key": "C30DBBFFD2A16E98895BD9EC2D7E724C", + "v1_mic_short_salt_identity_token_hmac_key": "B0B97E8EF4DCD33E40356CB2D6D7359517FCE3FFC7B8DBD4D73FAE87CE0D0CB5", + "v1_mic_short_salt_mic_hmac_key": "7AA526E8ACBE888A47E7F042DA3751FBF8988294D8286208122C55C2322D5F25", + "v1_signature_identity_token_hmac_key": "5EA50122D84E384D7C4B2105A182BEEC7A4D8CBE266B54C51D70F2186CC821C4", + "v1_signature_section_aes_key": "E9E31EFF10C7F9F2634BDB89CBB407CF" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "C543", + "expanded_salt": "4C4AC44FEA185B78FB54A3A2749DC65D" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "E4E6C206BDD5477A4894F465", - "extended_signed_metadata_key_hmac_key": "9274B9E3806FFB99E2D096597B8716E0949486FF30BA7A1FAB01FB5D143E5E30", - "extended_signed_section_aes_key": "5E09FB429564270B1E01C0C12064457F", - "extended_unsigned_metadata_key_hmac_key": "AE2B21B4DD683EEA3815374C1E606EFE81B3012A20C244F3EF44E4B126C1B060", - "extended_unsigned_section_aes_key": "4FC383A9EB6FC92D4E550C0869BA7424", - "extended_unsigned_section_mic_hmac_key": "A2D2F07EE970FFA7030BC81DB05D87AD7A1CF60E45A0F607F7F7D6CE64E7FE1E", - "key_seed": "06E34312B7BA188C16BF9EC455B7C3DB7BFF273ED7E671DCA6218923F6315EAC", - "legacy_ldt_key": "9A779C0695146D84379F839C1B01410A77838D4627A16D697AD8BA062BAF892C0518FF10250348929DD369E8A6B0D41076A485B48287E01F9D28F76A7AA93C25", - "legacy_metadata_key_hmac_key": "802F06CF894D4A44E91C384CD4CA11282E443D9E44D9A038715A3CC889DDCB19", - "legacy_metadata_nonce": "0918753240B432ADA508D2A0" + "v0_identity_token_hkdf": { + "expanded_key": "D5E805DA2CFD12C67BBC380449E48324", + "v0_identity_token": "095409BFC1116FCCCD80F1ED602B" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "B28E", - "expanded_salt": "27122881802D23D4B730928B317AD649" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9D8B", + "short_salt_nonce": "FC8A1484820906156C195098" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "A60426318C060F541DED5C1F7AFA6E87", - "legacy_metadata_key": "4EE9FB0C014E5C8DEC62CDCE3A54" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "E4CC4A82D88EA39A5187A28FBDD40F3D", + "derived_salt_nonce": "B5807E2B08DE99DC9EA01E9478282DDF", + "derived_salt_third_de": "E3CC102DB32458B2EAFEEBB6113DCEC2", + "section_extended_salt": "2E250B90A61C0F513340D930EA6571E4" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "C9264AB98A5CBEC98A59B436301C9456", - "derived_salt_first_section_no_de": "75AA3B31D990FA958C0BAB07C316137C", - "derived_salt_first_section_third_de": "20F8C6AA4C641C3EBAC513410853A637", - "section_salt": "63056BE924D9AF7A4E1EDFB78F8FFD42" + "key_seed_hkdf": { + "key_seed": "C458B31EB8502A483EEE8D5A804249BEFC113FA503018A2E65E91AE51F661839", + "v0_identity_token_hmac_key": "7681A1EA463DDD1FF1B10F87A8FBFB4C2069594DDD3B552C097154307BABD2FC", + "v0_ldt_key": "39C6E02DAA80BA8207A150BDA0241C3650F128706F413B9094997C661F0B722AEBD00042675F9BBF574A105505866B688EB115AEC0DA430BBB3AF5AA2B3B082E", + "v0_metadata_nonce": "6CDDAB688C8E27055A4C7735", + "v1_metadata_nonce": "E6B46B1329265F0BC3647652", + "v1_mic_extended_salt_aes_key": "5EEE9AB4B0A14122DA37583240569EEA", + "v1_mic_extended_salt_identity_token_hmac_key": "F0721E6BFC42BC07755E5838705139246B39637F18E9D6DDF8EB76E8E7BA64C5", + "v1_mic_extended_salt_mic_hmac_key": "D115FE4B3ED3D6FF3C457411F89EEC573FB6B4FF074844250F10D923416A951F", + "v1_mic_short_salt_aes_key": "10F209765DD1E2848DC419C4268771A6", + "v1_mic_short_salt_identity_token_hmac_key": "9FD5A74F6EC544AB29AF7CDF130FEAB9D22B37A4178E7A4C7703DCCE6AEAF4C7", + "v1_mic_short_salt_mic_hmac_key": "DB1E2E8F93CB7D9891CBC951DDF02E89B0E77F646EDB9BB4A33F936F7A04F693", + "v1_signature_identity_token_hmac_key": "419EA078DEA8DE15D57ED34A497920F671D83425B204F2C364CA506B2A4FFAE9", + "v1_signature_section_aes_key": "519EA77C6FFACDF488BC05BD1E45C56D" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "C2F8", + "expanded_salt": "D20BB79365E7FCB7B41D40D18B29D56C" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "641A9E897828B9CAD7C16FF8", - "extended_signed_metadata_key_hmac_key": "690679062F05D8BAC47BA64D13F91029084631B9FD39696B64702B533283C8F1", - "extended_signed_section_aes_key": "A521430F5CF09B5073A2EE5DCA704962", - "extended_unsigned_metadata_key_hmac_key": "2685C8CB006301455AA48F317D812AFA9F36FC071A692A7E21F411CA4B203E26", - "extended_unsigned_section_aes_key": "ADE5DC26FA3ECD51A6B4BE7B2EA0C70A", - "extended_unsigned_section_mic_hmac_key": "D8AE4269C81599401F6DE7805A5DD401BBEAFCE68BCF3245E315940130C041C5", - "key_seed": "41ECB16B981741F3FE1EC685A601EA8FB5F3B26ABAEC70294805339C90A8AD71", - "legacy_ldt_key": "8A6B4B8EFAF5DE8701684F7470183A4046FBFEE965E61D4219E09F95280D43B895BC9FE4B39499C927FF0541F067C95D98377D139CA23D19AD7B729F75207BD2", - "legacy_metadata_key_hmac_key": "D9A2131A2E99553E598BAACC299C5E40E3051A4E4244F3FB8705FEACE0CAB3AB", - "legacy_metadata_nonce": "862DF488A461D0EFA780FC19" + "v0_identity_token_hkdf": { + "expanded_key": "5436E96BB1FA5BEA3F61CCF4D1334D7B", + "v0_identity_token": "01395F4809126DDA6EDB05CBF274" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7CE1", - "expanded_salt": "72F031CD4FB7AB7A03423FBF04BA2A9E" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "D382", + "short_salt_nonce": "AE407828507152FA369D8AF9" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "07EDA657E63FC8F6737B5B3F4A0A8C81", - "legacy_metadata_key": "F141D580CA3325C5FC485E552438" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "93A5A6F16A869EFF9F4147B3BFEE2779", + "derived_salt_nonce": "51BA87FE075BF338688B780493445A1F", + "derived_salt_third_de": "534680E817F3E8366D19AA564ECC2ECC", + "section_extended_salt": "58FE62A2B35E250EC7A5F7885357E659" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D9498F72764DFB0266F773788284BCC9", - "derived_salt_first_section_no_de": "2736F330B0FC8CE3AC39558F48513039", - "derived_salt_first_section_third_de": "2B485FFF58AC337F216B01885F0A1FEB", - "section_salt": "482DFB90D8B4501C8089AD97750EC132" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "F1FA2EBDE91BEFEFDFC7CF00", - "extended_signed_metadata_key_hmac_key": "B1DF6DF11C98D5BE667BC5CE8B91321CC5498F9149B0217D48BA9C6E81BE9074", - "extended_signed_section_aes_key": "D63F841B59C4398735CCE79146AADC3F", - "extended_unsigned_metadata_key_hmac_key": "37A581DC364BB86DDC2AA8F8A1B939A7A92BBA83CA3697408D1CDED5699A4243", - "extended_unsigned_section_aes_key": "20A1EA0E7454FEFBFF4DA2BB4DF6CD8D", - "extended_unsigned_section_mic_hmac_key": "2842AAA512670388A45EC3DF52356B28AE1F7C3CEA324BE4847E9D8AF578A5DE", - "key_seed": "37399B354FF258D23A87941C4E9A348D851C5CAB79E1DB345BB2568841ADE7B7", - "legacy_ldt_key": "070759E454B3EBE99755C4C8C6FF67BB9DEA89D49A2CB68E02D3A4E66F12D1F97862F8A8B8664CD80A6F17EE9372170908F47B70681CCD6673019505E4130542", - "legacy_metadata_key_hmac_key": "535D5A54192D3E58EFB23C815A099924B2602137D8E12F6279A24077E232C3EA", - "legacy_metadata_nonce": "04B9108D0FB4A41EB17D754A" + "key_seed": "CAD145B4C4E7B40281586C90415BCE0B1D259E400C12A4558F848D4DB3FF6022", + "v0_identity_token_hmac_key": "094878A6B8D94529F33F759B6470003F5EC5D9E9D12D76C245E2E839E98C855B", + "v0_ldt_key": "23B0AA6A58D05FA25ADAB4395B948F2718CE48537875D2E68DDDFB38690D96B9A36913007ECF4A030BA7E00E96A7DA7BCE138FEB92FA1A4569F867EC2D881E18", + "v0_metadata_nonce": "CBB1C6591A06FBEF5D13C1BC", + "v1_metadata_nonce": "B3406DFBE1D1320184D9721C", + "v1_mic_extended_salt_aes_key": "0A47274588CCF8ED3772C654A76F7558", + "v1_mic_extended_salt_identity_token_hmac_key": "70FCDED0EA67404EF350C5167978234B681BA624C27334896364FDD77C4CCCBD", + "v1_mic_extended_salt_mic_hmac_key": "4EA92D6148AA2F61D283E1DB8AE6EE1066893C4A898BA503145CE493F2AD5400", + "v1_mic_short_salt_aes_key": "83F56E946E80C574D9A6C89975DEF2DB", + "v1_mic_short_salt_identity_token_hmac_key": "5CA60D709F88F9D07556B4A6E6A4CDE9DF1DBD280BABA39BE47A13FE90E5E27D", + "v1_mic_short_salt_mic_hmac_key": "33E1065D5BA0349E161E41D873B194379EEF0D2DEE466805D72BBE01F6349F2E", + "v1_signature_identity_token_hmac_key": "58A6E794B4593108761562A3C74CA4EDD345EFAA08F35E661B97FF113C24B6A6", + "v1_signature_section_aes_key": "1DCC7FBD666A58BD52FB5EB65A63251D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "D6EB", - "expanded_salt": "83EB2FECC0F1C19A6EF7FB30E945C103" + "v0_adv_salt_hkdf": { + "adv_salt": "94D8", + "expanded_salt": "0F9CFE35B1EB9C140FD004A84FF23100" + }, + "v0_identity_token_hkdf": { + "expanded_key": "FAB1FAE5BB91A22DAE1792117AAAF36A", + "v0_identity_token": "2A341B1B61F1ACFB5D74DA044867" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "7A1C", + "short_salt_nonce": "E006CD94A4539C0185D8A480" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "60C52A4D9245D6E8D49DB7FE7FDA5C43", - "legacy_metadata_key": "4E2117A0CED10CE233750FBAB835" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "28AFE5F7B2249029B8C64188C46E8EA6", + "derived_salt_nonce": "72B2C14A669C5CA1684D7E4751793E2F", + "derived_salt_third_de": "93DA04162B18AEE23A3056DD6B53B447", + "section_extended_salt": "E3D5BA66BFF1542BB9E864F1718972EE" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "849B406AC1383E3333C4526823350AC8", - "derived_salt_first_section_no_de": "F2657BBB7FB8879E98F9D4EE55343AA4", - "derived_salt_first_section_third_de": "9025C1E15E5668F1144640D7C2CB7F63", - "section_salt": "971929C83FBFB8552FAC4316895F82EF" + "key_seed_hkdf": { + "key_seed": "4ACA5648232134F2F67CAF1F73A747C79F05C5433006D6B0499E41C99CC7EDC5", + "v0_identity_token_hmac_key": "E5BFAB30F0CDC766E0A2CCAF2748F1C2D3A4C61F807EF3065AA632C1E031849C", + "v0_ldt_key": "8E8A67DCD76DB26CA1F35044302978C4981B6934A03F8431C737D66529E88C752B6B85C8585C3C4F5D321DA0C8297BB6112CC63878C69ED84C97EDAB95AA5BD5", + "v0_metadata_nonce": "6457431AEFBF8D2360A0892F", + "v1_metadata_nonce": "2307C5893275080E5C6B7A5F", + "v1_mic_extended_salt_aes_key": "49F7F9AF2E1AAE200CA362CCB2D8DA5C", + "v1_mic_extended_salt_identity_token_hmac_key": "DDF91ACE824007F30BD268501F411F2926B578F675DA58158B12ED67C29DA6DF", + "v1_mic_extended_salt_mic_hmac_key": "5D68D65D0C1926E664FB9DABDEC88B84A1151479045FF66BD520E496DA11BDE1", + "v1_mic_short_salt_aes_key": "4201A2259722BA7647492CD28EEC1AEF", + "v1_mic_short_salt_identity_token_hmac_key": "B827390AAFDFFE4121E501DD5AB0F63FE99812B0AA19EE5D3CCE8371BA8D8565", + "v1_mic_short_salt_mic_hmac_key": "14E7069440F3314D316424A4C05B14781FB8057BF555056B4DCC1CCC01CEA5F6", + "v1_signature_identity_token_hmac_key": "CEF4CC2BC66B6DA8CDE0BDC33CDB0544A482E693D0AE8E4776D2C50EB3141EDA", + "v1_signature_section_aes_key": "26D03E938464532CBED815DE327C0E53" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "5883", + "expanded_salt": "107D3AF4F533B1415860BB88500FF30E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "BAB6E78DEE99392F09D6A045", - "extended_signed_metadata_key_hmac_key": "FE88421ABA3A3E0DA9E519243749AB2B28586480DB9B59C41F7E4AB17A9459CF", - "extended_signed_section_aes_key": "EB1F668BACAD4DE4555036C8B9F21D9F", - "extended_unsigned_metadata_key_hmac_key": "F7016A22618D636539DD37221EB7BA8BE8764707AB9DEBA695FAE93546E1E777", - "extended_unsigned_section_aes_key": "7AF856E9EA5F3AC6EBF2DA80EC065050", - "extended_unsigned_section_mic_hmac_key": "17738046ED5E72F0C379D08FE6A815CDF72CB1B8BA2C675DD013872E7B0DD185", - "key_seed": "185AF89CD890AD6F7C0F9DE8228DB8A92AE25DEF3BE510289663D4C196FC2CDD", - "legacy_ldt_key": "3659A65B725059278CB5ACD34B73F32EC5D8D267C15E567BD4EEE489618EFA62D03DF9A8C77D3B407F107927AEB771EC613320B1DAE7A295FC49AC8E1B274F8A", - "legacy_metadata_key_hmac_key": "5F10B1A7CCA2F40E32B00738583CA2604312F1D9648EB375995EF725438B6B5B", - "legacy_metadata_nonce": "EE05CC8759A360B9699FFD9F" + "v0_identity_token_hkdf": { + "expanded_key": "B5D43495932EA4AAC04D597D47F3E1A5", + "v0_identity_token": "CDE1002866DA5EB5F1B93AE8604E" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "7FEA", - "expanded_salt": "C7E9D2070465A796CB27EA5E81D7B5C9" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3F19", + "short_salt_nonce": "725F8B5D5A48F5BF15805851" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "E4AB233100D9D776DEBA1949426DC104", - "legacy_metadata_key": "C5E5885E8041F9A0E290D0174FF0" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "ECE9232AEB13F080BBA9110F115C1C06", + "derived_salt_nonce": "B067DB848C67AB62F7D9647AEF6350DD", + "derived_salt_third_de": "0E171CFAF26BE107633093C5FBE09795", + "section_extended_salt": "98564150CD7F85177E2FBCD32D1991AB" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "582878C554E5BFF92A4C26C50BBC2B27", - "derived_salt_first_section_no_de": "C9FA9274CB4C3F6F03BB7F2AA5D70A11", - "derived_salt_first_section_third_de": "582276B5F71F65E87B883C86DEC83349", - "section_salt": "2DA2B6676B05EADBBA2AC2C7A1B91E5B" + "key_seed_hkdf": { + "key_seed": "1BE63378AB9D94C9624BF8AA13D32159AE60185DE029F75CC5ED057DA75B5859", + "v0_identity_token_hmac_key": "ABD803C6A6A5FC17BE165B565C5258A7B696BACA67F122314BAC5133D26927D4", + "v0_ldt_key": "458D845951F3C72999AD0D892B41AB1ADC8F1D257085F5305EB498CDB702BB32272353D4BF359DC7C0BC7348DE5CF83F92F099854742015D1703501620249349", + "v0_metadata_nonce": "DC8B506C111B985C7CE1A61E", + "v1_metadata_nonce": "D086A5209230EB1289F25BEB", + "v1_mic_extended_salt_aes_key": "8A8CD0757997B9A09368E004C13A5907", + "v1_mic_extended_salt_identity_token_hmac_key": "9F5E33BB0AADE8FA3B3EFC1C0ED59446D9F5D7078CA6B5A268B4FCCC24F7EEB8", + "v1_mic_extended_salt_mic_hmac_key": "7175D3D814EC85A2D0425C56E3AE38B7380FFF95C51104BAA187095753BA574C", + "v1_mic_short_salt_aes_key": "50628611E98D88D30CF256444B776072", + "v1_mic_short_salt_identity_token_hmac_key": "D8347CF2051CCCE1900812130C256F539172A7937BB9F024C101C61BD11C0767", + "v1_mic_short_salt_mic_hmac_key": "46D08AF025C2B6D0B27D54ACC927D0FB0CE944D38A5611BB15DC7FB71864D468", + "v1_signature_identity_token_hmac_key": "8B4C710326841E386DB89A9E34140A3129F740253121E150E59F86AC03B7BE9A", + "v1_signature_section_aes_key": "F72965CB64E9365256119F29F5355A04" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "D584", + "expanded_salt": "93356D355D4FE32E21F4945687F768BA" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "1516355E155E481A2C1BC292", - "extended_signed_metadata_key_hmac_key": "A96AB799DBBF000DBD6429124DF1AB94AD26BA8EA3CFA2BD3685D18F74AB95B5", - "extended_signed_section_aes_key": "2EA7AA6081C6055A50D2BA83F7650ECE", - "extended_unsigned_metadata_key_hmac_key": "54D6DE3AB30E06638AF867C79CA8F291499A6A912964EDAE3FFF06D75D6734FE", - "extended_unsigned_section_aes_key": "FCF1C0C04D383C2B440E91142D5F8DF3", - "extended_unsigned_section_mic_hmac_key": "617A0B559B6C31312C6DB59956560DB2200B0DA19132085BB51EEC4662365BEC", - "key_seed": "BEE55110B49523CA92D9CD1921A3A3556D3DAE9E7D2DC1DCF809A7F744D744FB", - "legacy_ldt_key": "3050E135E4A609B600FA94D673AD60C6800F860CEB26E0C080669174F4967FC877241054D94C945CFC4F511404AAB3941EF5337E49A3C0357DDCFBEE6D0FF178", - "legacy_metadata_key_hmac_key": "D4CD2F5513409E9C08796B367D68ED86E7F8AA1D73B3BC80E310A6A89FBB5AF1", - "legacy_metadata_nonce": "69BBF34C4C06F9098ED5822C" + "v0_identity_token_hkdf": { + "expanded_key": "087F0BC622E59911C61FEC7AC6D5CE8B", + "v0_identity_token": "D8D6DE28153FB1F87CD75FBA7F61" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "E41C", - "expanded_salt": "F90A3A5A7E184026B2412B7981E6E4EA" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "B578", + "short_salt_nonce": "011AB27EBDDCF76BECAC83E1" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "7CBB4317E53C77A6EAF04270340C8E74", - "legacy_metadata_key": "290406B8E4F3FDD69F77100C25F8" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "9E43D77377463D53AC57DFA860AC64F2", + "derived_salt_nonce": "CDABCA09C3FE20F0BFD2F0855C16709B", + "derived_salt_third_de": "2A7BB2161625A9FA4C944A03780FE0F7", + "section_extended_salt": "C3AD1D6CF13D0ED5D4B52933E4BE9923" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "09C85DC366B0A127E44BC3EB55F1B69F", - "derived_salt_first_section_no_de": "8E806978646803E71CF5A89A993EBD15", - "derived_salt_first_section_third_de": "A79CB0BE50F815A706B75686E8AF95A8", - "section_salt": "BDC5C3A2FDEFF52154DBEE9B2DC99272" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "38347176312E7BF0CFC150F5", - "extended_signed_metadata_key_hmac_key": "AF37F8DDF621E95E9DF9E960D7C3C3B204CF5F660E33015C0F76E1FFBF793255", - "extended_signed_section_aes_key": "DDCE8B724FCB835C5769FC12FBBBCFA1", - "extended_unsigned_metadata_key_hmac_key": "2A31672AF767AD1C20F69A40FC0C39E82760A88CF7FC32AC562B4334A3BB6FE1", - "extended_unsigned_section_aes_key": "A6DA0A55C2DF68D9A268E2E7D5DFA910", - "extended_unsigned_section_mic_hmac_key": "842AC63178D49573C9A294B11B23053A8D7D032E2092A7B090B18C3B4B1B0D41", - "key_seed": "5507520DCBC7FB26D474314F10DE9CA600A29F7EA2B4EE3FCBA75A79812410EB", - "legacy_ldt_key": "13FAD5A042A94E5BB18ACB097E8D9AC9BC3212ECECCAE8B3F0877B28BE475A00F055E916510D5E37B70EBFFC6E20281A98E960BB875B6CA04DC4A4D791D728D4", - "legacy_metadata_key_hmac_key": "D208CCF899D7738EFA94AF2F50D71E96A850ABD8DEA1E731513BF959E52245D8", - "legacy_metadata_nonce": "55869FF688A156A9AD67F4B0" + "key_seed": "EF9F19EA27A76CE0EEE32D179274DFC21FF9ADB2DF7A94905F796FC6AB976867", + "v0_identity_token_hmac_key": "9B83E478395DEC9B396443937B6E51290E28FFDE2449CC2987C2C75AA91E8BF9", + "v0_ldt_key": "FE74DCBB424B6F9D9D31F31CB047176E2CE8B3565149201F01ABA127DA935BA97351D6536ECF0AE1C5E1A73B5E651338E7290BEDC98056E369372A5AB036C8B4", + "v0_metadata_nonce": "238DC3B985343E54213B4F84", + "v1_metadata_nonce": "830717981E766A8D5EF618DC", + "v1_mic_extended_salt_aes_key": "D99AE5B345134E9EB7FD31344806ABC5", + "v1_mic_extended_salt_identity_token_hmac_key": "FBDDFC1B6102418E55B29C6B1F5C2A6D5E7CF796272E8D4CDB8A212FC5844487", + "v1_mic_extended_salt_mic_hmac_key": "279FD3C9459F9752565AC221A02805DCB2860DEE54FC5FB6787F3ED26C327463", + "v1_mic_short_salt_aes_key": "9A62AE0DDB8B45D2E6B1A5C34576D29B", + "v1_mic_short_salt_identity_token_hmac_key": "D0FBCE82CFCE356C430CB45A87CAB367C0F43F2D512F996854A1E0CF1AA230F8", + "v1_mic_short_salt_mic_hmac_key": "35DD70B190738EE311AD7A9169E9831C6DE663A038BC30F744B73686264D868E", + "v1_signature_identity_token_hmac_key": "57683A7ECCAF59E1233B5972B29A681EFB5C5CCC7841A59F200562F43B604955", + "v1_signature_section_aes_key": "3992116A5B3CB5E2909EBA148CA3D0C0" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5D87", - "expanded_salt": "6CD22F42846D18DEB8B16AEC28055646" + "v0_adv_salt_hkdf": { + "adv_salt": "3484", + "expanded_salt": "0D2B068736CA05A30FB77F4CB162D6E5" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "67C50D4BE0C807CC777A451E55290706", - "legacy_metadata_key": "CC56E75A8BB54C3CE1EE9DAC6855" + "v0_identity_token_hkdf": { + "expanded_key": "0FA4D93D5FB8710DD7B74B82030EFAC3", + "v0_identity_token": "DD024CDC610F1298061F59286313" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "A665", + "short_salt_nonce": "D060E783D2A0CE06655119EC" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "2B2E1D1168C638E5F96A01EFE95E9198", + "derived_salt_nonce": "42F31D89F5FF91B8CC141B2555261E94", + "derived_salt_third_de": "9ECC9D55DFF824E87A7C10427EDB7D26", + "section_extended_salt": "9CF4B88393E26CA09669F2A24F0893F2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "724B63781CDFD0DE57D682E929C0F1AC", - "derived_salt_first_section_no_de": "DA6C22EBBD2E4FC58307D725E7001E18", - "derived_salt_first_section_third_de": "70E96C64C5013DDA87D8750BFC734CCF", - "section_salt": "60922665EAA6734D3AC84D0BC6B8173E" + "key_seed_hkdf": { + "key_seed": "81BE1F6A11DF23604652C9BE0BB40A5082107EFCD943A13F4804E11C55B0EE76", + "v0_identity_token_hmac_key": "B7C2F66D0712E43B3D7A791F1D6B33AEB5FDED682B54F2FDD1E616C5D6ED1AFC", + "v0_ldt_key": "6D3F8AA49C7749B49D6F62AC6AF4A9EE6BE43A50C64D7D9C3C17A21F67BAB89B4CCDA8BDE1AB1E5A287DA1427E1F92F43B78BA2CF12F151EEF68B5FDA962C89F", + "v0_metadata_nonce": "1E59D995D9364D1F4F601502", + "v1_metadata_nonce": "B55540E50C46A2FD3AA6EE54", + "v1_mic_extended_salt_aes_key": "C99342BBECF0C67F095FC1ED24C4C4C3", + "v1_mic_extended_salt_identity_token_hmac_key": "98A3EB8EE5B99369FDA984BE76A1F05FD7D51DF6D0983C572437CB40B87B5C48", + "v1_mic_extended_salt_mic_hmac_key": "1FFDBECE1FB5B98AC89B7AC112608F8E7705C1C98F2434DEE5529232CFA16BC7", + "v1_mic_short_salt_aes_key": "3A7608329B686BEEA3B22FE3358B1310", + "v1_mic_short_salt_identity_token_hmac_key": "4B4C530D8FD05FB35D04618172CC0CB522F1DB01D91665941DD62B9179642D3D", + "v1_mic_short_salt_mic_hmac_key": "386F86CA17343F3A66426BD8B626682D9F4AFDF77AB93AB964FAA3708E9100F2", + "v1_signature_identity_token_hmac_key": "9D9FBDEAEFA4D07C54302BDC107B47530E461D428A4DCBA4C20B4339053FFBF1", + "v1_signature_section_aes_key": "D8BB6D91F80D467B55F348501483688A" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "6195C05F850120907C37E671", - "extended_signed_metadata_key_hmac_key": "C197E6E017FDECD561EA88AD8CBF7F9826B17CC993E15803C2B770DB98803F71", - "extended_signed_section_aes_key": "0400A8E1E5D2A6D93FE2DA13E109D10A", - "extended_unsigned_metadata_key_hmac_key": "DA4F587EA32EE460D0605AEFB2A3D4916137A0D27FE142D2BA315CFE40A7CF7E", - "extended_unsigned_section_aes_key": "97F44ECF5B72FCAA7730A06BC7E21466", - "extended_unsigned_section_mic_hmac_key": "1B2815943A5DAE1D4823E8B146AA3CABB59017B2D01E9DDA7731933E77354459", - "key_seed": "933CC9ED79D768475F2C50D65DD35E354AEC0ACDDBB1DB7A406B16A967262F95", - "legacy_ldt_key": "B3C8DB885F6949E585C9B9CFB8292A2E1D16DFAEB0D8B4CB859362AF85EEB78F55C676BAED4ED82FE690EB5A52DC194E3C09037367E0AF6C012DC33AFE024750", - "legacy_metadata_key_hmac_key": "68B1BDFFCEC2A954A0C61C07BA65A3028BB117945F0D405BFF859719E90C603F", - "legacy_metadata_nonce": "9368E6A9BFD9CA79ED0FCC4D" + "v0_adv_salt_hkdf": { + "adv_salt": "1CE3", + "expanded_salt": "25EAC881DD2DFD7EFA2973BDB0A3FB23" + }, + "v0_identity_token_hkdf": { + "expanded_key": "1B3976E6D6E9297D465A6E9EE67559E2", + "v0_identity_token": "4CAE44FCA940D2B49B1CDF558260" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2C1F", - "expanded_salt": "764B370D8ED153B4D9AF7326FD7E3131" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0891", + "short_salt_nonce": "F4BD7CB2CE01511C1F18A53E" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "6B947A303D99A9874028683C7663E5AE", - "legacy_metadata_key": "95E95ADB8AAC112E502641BB3974" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "541E5A0A4D7EBD30C3366C4628971F0A", + "derived_salt_nonce": "6D0DE80696F619D2B4CBA1D9DD0B7DE2", + "derived_salt_third_de": "DC761244E373DB2F195ADA9CCB849BF0", + "section_extended_salt": "829E9AC22DC10ACB10F1FE7EFE014CDF" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "699F64EEEE0A421370D20D1E656D8EF1", - "derived_salt_first_section_no_de": "0B9CC994DEB1CBEE31334AAE82BB01C6", - "derived_salt_first_section_third_de": "E883BA14BB1E9C1CF2CA544507A8E26D", - "section_salt": "93EC27FD11A0710A12D837043C9CB895" + "key_seed_hkdf": { + "key_seed": "C33B62DDC31FF779AD1F6D2383226D28789EB3B9BC4F28290975ED6587DA0B4D", + "v0_identity_token_hmac_key": "36C816C3AB161BC5691D657590CC8E7D4CED85CFE8A075357B94A00F30E3ED47", + "v0_ldt_key": "57E32F4A953427F5D8E6F1DDB9BC9F8A7A770D439E2D9B793033EC74211A8F34938E1FC524EA70C9895DD9872742F13FC22A817FADE748B3F5F0D6D28867098E", + "v0_metadata_nonce": "2A4C6A38F60B328CB449D269", + "v1_metadata_nonce": "4823300500BAB300C14A290C", + "v1_mic_extended_salt_aes_key": "30306339F33123C69725052DBC3DF985", + "v1_mic_extended_salt_identity_token_hmac_key": "50B0F5BE869B43E70BC61D249AC48A64E1FDBED45F239E545952CBBACA13171C", + "v1_mic_extended_salt_mic_hmac_key": "EBB43E51498E6753A1877E2C996330A2DF880E41887DDDED4FE7FF6D144CF4DA", + "v1_mic_short_salt_aes_key": "40119DA2ADBBF3E491019863938942E3", + "v1_mic_short_salt_identity_token_hmac_key": "9E82B5C1E723F1B578FE9A8519819B4A5B0D0F6DDAD0147E78BF48F778A38CA0", + "v1_mic_short_salt_mic_hmac_key": "2EA118DF0241382FDA2AA66599346986048260DACC8B1CA8EB6AF745224DB3FE", + "v1_signature_identity_token_hmac_key": "F31EB8FBF7E0170E352059413B935E7ADC5C8262D97DE0D81CEBF1176D270352", + "v1_signature_section_aes_key": "E780DDAB066C5FC692736EBE821C6FF8" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "8C118284D7A96BF2A60C1239", - "extended_signed_metadata_key_hmac_key": "C6CE919C79E1CB055C77D1213E9266D95C8B828D32E93F77A8EA73EA48C6CD20", - "extended_signed_section_aes_key": "6E770DC0F1C276CE1DCFB138E8005EC3", - "extended_unsigned_metadata_key_hmac_key": "2582C714334AAEE935486705696B9196C27A4EC495CB0E59C8601CD60831022D", - "extended_unsigned_section_aes_key": "255034A404E961637FCF4CE1CA72B44F", - "extended_unsigned_section_mic_hmac_key": "4216782A51DCB1997224685E06185109FEF99FA3354038A49FAE4F0E0076FEE7", - "key_seed": "562111357842DD6AD71E95C6B9DC635ADE5E2EC3A2E29A242117147A0148705A", - "legacy_ldt_key": "D258BC177A33B5E2256475FDC9F84AD78F8B4886EB8781B4F1926716A6BA6D527D75D2953CC4037044B14107A91B292A45DD46ECEA653A1D086283EAB5607FC1", - "legacy_metadata_key_hmac_key": "8BBC6480F67E0BB2AE62AEFBB16D97BFD4C37618E34B1982B29BA56B34FDB466", - "legacy_metadata_nonce": "3EA11851CAC5F5608CCCE44F" + "v0_adv_salt_hkdf": { + "adv_salt": "8118", + "expanded_salt": "B259AFC30A1526F524AB7D176239D332" + }, + "v0_identity_token_hkdf": { + "expanded_key": "FD4028D3275272ABF95084312992FC6D", + "v0_identity_token": "95C1A38B5345AF2731967010E3D5" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "1C18", - "expanded_salt": "A58037650FF49441923278D15FE312D6" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8F6D", + "short_salt_nonce": "E9582F01D2CBE7A7F61C39E8" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "96B7834CD34C6EE7027864BC6CC410FF", - "legacy_metadata_key": "B8CD0EC6CBB33A4601A522200869" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "47A9E3DDC054A4E93C11018129263A61", + "derived_salt_nonce": "04023B2ED6EDFD2654E91BB8604CFCB9", + "derived_salt_third_de": "FE7BEE522D169D527312F2EA7DCDCC1A", + "section_extended_salt": "F9696D41F224F85BF8A5CDB62C171144" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "B091260FEC73EE7A8D70201F9D464F83", - "derived_salt_first_section_no_de": "EE1D6CE31F19649C24841A7F6533AF34", - "derived_salt_first_section_third_de": "14FD75BF7AD5B802CE6725D9A4C2EAC9", - "section_salt": "CC587F388F406FC90B64C0AF1000419C" + "key_seed_hkdf": { + "key_seed": "57C3D798D37A8A013CFA9E360748AFBFDAE3BA89F545869122CD051E58331DD4", + "v0_identity_token_hmac_key": "7A85D2EB46CD2EA1373599BC94D8CBC6C6678296E3173CA3DDE74D4A80B1ED3B", + "v0_ldt_key": "86EDCA697E60EC4CA150BEC73AE0E8CD8F0A0E76F481E409CBEC6BDD93540BFE80C610C0782CE4600CA45E7DAE40FFE3143A18AC11124C233C484C92C8AEAA36", + "v0_metadata_nonce": "5068C44E8025E74D61C784E5", + "v1_metadata_nonce": "4228B89FA232A8DB0B5B0C25", + "v1_mic_extended_salt_aes_key": "743E02E60C3F633F37B073684C5A42A8", + "v1_mic_extended_salt_identity_token_hmac_key": "6A38862A238FEA6BBBB4FB72CE602404A26EA0F64D50FDD1D8C088B50AAD16A2", + "v1_mic_extended_salt_mic_hmac_key": "B87017DB360AD3F66B74E6F8779C485573CECE93A9B058E9197E08DE19DC233E", + "v1_mic_short_salt_aes_key": "C1802BB67FA9966A675459E93BB18E7C", + "v1_mic_short_salt_identity_token_hmac_key": "B9BF21CAEA29FDC085FBDD4D26DF28FE548C1B945952FCA25799D13999C1CD30", + "v1_mic_short_salt_mic_hmac_key": "9CBC02F56E1DE42FA95DABD085E014E5B1FAC3282A37B23D497F49DA81EF42A2", + "v1_signature_identity_token_hmac_key": "F556B76B0E1EE952A87246820380A53ADFC7928AE9A497F3CDEDCC72CB15F2F3", + "v1_signature_section_aes_key": "419C27C2E8899D21456C8586BB234079" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "218D", + "expanded_salt": "05D34EDFC849A67164C828BBDC95248B" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "0F1F6DDCDD98D829428F0551", - "extended_signed_metadata_key_hmac_key": "6BDD30B0682F92D8E01A1483C3B21887F0053B3E99435388C6DD41037EB51AEB", - "extended_signed_section_aes_key": "3F4604AD3B2C106C10BA72C3ECE5AE49", - "extended_unsigned_metadata_key_hmac_key": "874627B363F91A534891A9285E0DF0EDD15DC79E3E48A165B0984D4521ACAD7B", - "extended_unsigned_section_aes_key": "B103A43F35DC81696985B85943FC9F7C", - "extended_unsigned_section_mic_hmac_key": "4983A837EC95679DFBB7BBC1EDA6839C351059CF76E3465FCB7150E2C9DAA555", - "key_seed": "67E041F864141E3F2D046910D9F966739B5C393ACC320E68C5DA6017D4599DC7", - "legacy_ldt_key": "D8BB8E5985E39A4E64C54FCBDE74D1D5D3E27781C34AC260999F4FF0C06B0E1AE7A0E6D4099F9BF71BCEF921B24C85751314574F394891E49C8001FF56806572", - "legacy_metadata_key_hmac_key": "2BE0A55DA15AA8323C56AB17C946C6A4E539560BA87A85C656BD1EF2326300BF", - "legacy_metadata_nonce": "6E488DABE0EF2C8F5EDEE07B" + "v0_identity_token_hkdf": { + "expanded_key": "ABFE5A0FCD29C9FAC689AF6254F6A4AF", + "v0_identity_token": "9C4C49A50D448BB7C98961277E16" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "246C", - "expanded_salt": "A04B4F4D54258A3481BC4E119A6A2B62" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "614C", + "short_salt_nonce": "B726D470FB3C62E5AEE6F3AB" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "9DF4EB64B8D5D2959CFD9D092BC37B17", - "legacy_metadata_key": "5505114A304DFA404B9258AB6AF7" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "AFBAA77C37E2F2E4C4BEBD7A7A40E8E8", + "derived_salt_nonce": "666C9A35AA6DA090BEE448E331D2201D", + "derived_salt_third_de": "89EBB1D894E43156911A709CE348F664", + "section_extended_salt": "606E4773F79F85943AD21CE692D8F5BC" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "92F14175B1DFC4CE170902636E42713E", - "derived_salt_first_section_no_de": "4156C04BB9AE6EFA9DEC3233CD5A305A", - "derived_salt_first_section_third_de": "3C58FB419F0BD045E235ADC4352676DA", - "section_salt": "FCC5C8C0A905123991DB1963CA187342" + "key_seed_hkdf": { + "key_seed": "28F45CDB8E3C5D060AEB3B400E9CADDBE8BC5635375D1B847A0CBCF3F6959E36", + "v0_identity_token_hmac_key": "DA584FB27301FAAFA8DBC3A3055B7DB704AA5FA842C4BFE9DCC8402CCBD6B230", + "v0_ldt_key": "382BE0817D6EFE8CEFFE2AC75029ED0FB52EA917CD74DEC4146FDCEC8AAB0E40B9D7E540D4E6808C4FB6D3F7A4470D9E9C276746A9BD0E7B7A64D5E7483EE281", + "v0_metadata_nonce": "4250F2C00B4540833D26C980", + "v1_metadata_nonce": "57EFEB1654A4C124C9B1EF4C", + "v1_mic_extended_salt_aes_key": "52562FE1226DFFB4025D2D34C17CABD6", + "v1_mic_extended_salt_identity_token_hmac_key": "63DCF0E160424B71FA8769F159F20224F2C36DB2C285EA191EFE891784526290", + "v1_mic_extended_salt_mic_hmac_key": "1EF4654DD267EF8ABF0C7B6401F0A108AB7FF39D11593C1CB836C1345312F92B", + "v1_mic_short_salt_aes_key": "F7906C1B9382A8AA9E30D58ED937126F", + "v1_mic_short_salt_identity_token_hmac_key": "F26237F030DABB04BCCDAB8B927C86C6C5853C2608C39FC574283140E7CD3D65", + "v1_mic_short_salt_mic_hmac_key": "387BAD7E4C92B13271493360484B2AD24C8C1DE146CB4AAFD8CB2F9046E57058", + "v1_signature_identity_token_hmac_key": "E31153728A02DCA8CA2D2F697F0772E77A92C4483B7CB99E61542B79FCDDA123", + "v1_signature_section_aes_key": "AA93AC9530BC4E822430C4A79A898D03" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "2914", + "expanded_salt": "8AD51A4D7D8C14145E398607CAFD6008" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "E6CB1D645A1C322DD231C530", - "extended_signed_metadata_key_hmac_key": "6541D917FFD4EBE53C09BF098B18DADAAA8DFF5ACBB1356BB3E1439EAE91E399", - "extended_signed_section_aes_key": "A5C69E0BB040A4ED7AEA8D202D1AC1B6", - "extended_unsigned_metadata_key_hmac_key": "0F3C39ABFB77F95C5B015829511A821DC453306953B33D12A1D0BA5F2E48F3DE", - "extended_unsigned_section_aes_key": "F73B279C87F7D8145D53BCE3FBE49FA2", - "extended_unsigned_section_mic_hmac_key": "C386709CED7BF9873F36D764C601B3DB06FFF096993FE59E2C2E7A2E06C83ECE", - "key_seed": "66BD6221C1E30871D422B67F060C9E22800A834DF098843BFC648B76E54ED908", - "legacy_ldt_key": "79204103FD0DC36158434265D60D9D4A7CDF2569D1A855CC1C0A5616298C41E07A25577E028C13A4C517D2BEBCFC6F2198710BE7573B7C0C70E73BFF28C9710F", - "legacy_metadata_key_hmac_key": "FDE5E6233F81A1DA995A94969207DA3CF835C672B2C4A5F65D36AE45B2A5D2A1", - "legacy_metadata_nonce": "57EA5DBE1D8D34591922A866" + "v0_identity_token_hkdf": { + "expanded_key": "4D70AC76CAF34E091C8D4A6C59C7E2C6", + "v0_identity_token": "DEDA6A2C50578DF5DC97C211B9D4" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "AE61", - "expanded_salt": "EE04115499CE6C19FB6BB2610257A5FC" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9051", + "short_salt_nonce": "9B0F55835CCBB056C630C3D6" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "45FE6BCBC3E86F2B10458F44DBC73647", - "legacy_metadata_key": "D9B336A4E52CB722943FFD9CF784" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "5B7A957680DBE5A18F6D47490EBF2839", + "derived_salt_nonce": "FA772F27245390D3125821597FB8D0F9", + "derived_salt_third_de": "62B187FEFED14F6E4B292E06BC94A19B", + "section_extended_salt": "157D4AD5BC9A70486F2E15EFFBA52500" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "6919D48644FFCB351097E0A7F63BAD7C", - "derived_salt_first_section_no_de": "B40EEC7CA7711C443BC6131AE1209711", - "derived_salt_first_section_third_de": "EE87CC5CE451FACAC62DD63C70F53BB3", - "section_salt": "E9C2AB1A142AAD88D5B3E8ECE861F46C" + "key_seed_hkdf": { + "key_seed": "39518BAA6A95173EE46FF390762FCB1F60E9B6A2B8C44DF4133289F2984E1033", + "v0_identity_token_hmac_key": "964C1DFEA2AAB348F63FA5CEFA9D994DE2C16C5F0EE6D684F2144436331055E6", + "v0_ldt_key": "697FE42DCA3F0390137D789BA209E5D2D31EEA10CDB038D2D17445738293359543EE36DAFDCC214738B0C4976144CAF1C885CB26C2C749CACEC8E0A2B9B558A3", + "v0_metadata_nonce": "0D22B7BD15D4EDB6CBFD899F", + "v1_metadata_nonce": "BF4DCF73602F6ED1AC6E3B0A", + "v1_mic_extended_salt_aes_key": "DDF87B5AD37C73133F051E19D73958BE", + "v1_mic_extended_salt_identity_token_hmac_key": "8C1943E117152BD3550B99EEF815EF9B533501B7CEA6277BF6BEE4A3A76DC7F9", + "v1_mic_extended_salt_mic_hmac_key": "5CE6F847C64DEAA632CBDA32769F18763E757E80B1746AAB191F638E0833C32E", + "v1_mic_short_salt_aes_key": "0544AFBF786E3F4C01EC50AB2AD04DA2", + "v1_mic_short_salt_identity_token_hmac_key": "A1DB27DB83EE9FD2C756C67CC8FB993286CDAA5895E7C3012E540F32D46EC046", + "v1_mic_short_salt_mic_hmac_key": "000B1436329CFB45BFAEF8BD5A0DB872D2951E54FF56BEAEFE4063407BB02F5C", + "v1_signature_identity_token_hmac_key": "A768835197F34ED548D340389920D4128507BE77BC0E13556EF41E95C34CEC3F", + "v1_signature_section_aes_key": "D23318460ABBDFF8B79B7B7977564BCB" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "1F7415759E6AF70ED5ECFB8B", - "extended_signed_metadata_key_hmac_key": "4C52B8B27F4405B995784DA1A19800280D7790F02E1A4ED718AFF3B9D2CFB632", - "extended_signed_section_aes_key": "E39A23C3DE620D184AD6717B9441B453", - "extended_unsigned_metadata_key_hmac_key": "D97C790467145FC66B8962922BE7163D01E72398E58A7381E94E52205A99C49B", - "extended_unsigned_section_aes_key": "FB9F25B845153CD75A97C8FCDA32A6B9", - "extended_unsigned_section_mic_hmac_key": "7F291513A23A7AA803A1CD8DBA7A9DE24180EE1580B31E3AE689EF51851EF266", - "key_seed": "C76E4012BA6DAE4B2CC7DE0FD6A60790E7E69183D4C894EEB2C14F55F691D200", - "legacy_ldt_key": "02D0233B56EB07765A584139A7791E9E338698C5C16A32B89973A921DCE26B483E7322D354F8D597A48A67818E7697686C9416CE10A2FD5B5A153A80EF0C3DD7", - "legacy_metadata_key_hmac_key": "D3BFBF4AEF2B0EAA29B8C0A4A5A8E140C9861C55AE77939A9100863458F73A48", - "legacy_metadata_nonce": "3DB25905270EA45BDE8B2C78" + "v0_adv_salt_hkdf": { + "adv_salt": "5EC8", + "expanded_salt": "DBB2415837D9360B31C4C27B45D98643" + }, + "v0_identity_token_hkdf": { + "expanded_key": "48D5A14CE83B030F33DE6D9767913D1E", + "v0_identity_token": "5A4832D02E177FF842083118FFC5" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "C0DC", - "expanded_salt": "51AFDF06C286189BE2A38DF2AC5C157F" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "3F81", + "short_salt_nonce": "0D5A7220B52241C711F8A7B7" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "DBFD6CB8BEF948E30034942C217AB49F", - "legacy_metadata_key": "A6572C02A89BFC53CE24AFE726A5" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "7A4EC90B70FA9ACC4A37F691C8A62363", + "derived_salt_nonce": "90646E267796BB4D06D9DA6332CFC0B8", + "derived_salt_third_de": "C76CC4B946155D059264B51412240813", + "section_extended_salt": "8B7B2570D21C35A39687CB7725B1D8DC" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "F0C2D07232D5E955E8C82CD835B56E1C", - "derived_salt_first_section_no_de": "1F34BDC3807F158859A6FACC33B76BA6", - "derived_salt_first_section_third_de": "8B547F100FE1EAD817E8DD7AC7FA6D7D", - "section_salt": "E887AFFFEBC6CAEA000CD7B2843AD21E" + "key_seed_hkdf": { + "key_seed": "AA2716AF54865437571682DC3C6FE92AA8722F322CA961BBBC7459CE841F960E", + "v0_identity_token_hmac_key": "4AD019A61785FEB251708EE927933E062B348CCA84968642EE881FD2D7B5B69B", + "v0_ldt_key": "BC65180931BE080985DE03CB0FA3604413E3660D30399A600F5A723A97FFBB64FAE25464CEE6D153A4572EF1F8AE483C95E1159CDFDB9BC338C29D0F7E28B1FF", + "v0_metadata_nonce": "262FEDCEAB01B2888C2F284E", + "v1_metadata_nonce": "D948EED446410C58F2B5473E", + "v1_mic_extended_salt_aes_key": "4D9FB04B417FE0C515441BBB5A24D4DD", + "v1_mic_extended_salt_identity_token_hmac_key": "B8CACDDA4B647401AFFA0E64C79A3D60E321CAF15EE406665740F9C4DD5CD6AB", + "v1_mic_extended_salt_mic_hmac_key": "D6BF2E0C532A2297799A495F52F5830C47E8D121B07A7600A12ED6DBB6CD1167", + "v1_mic_short_salt_aes_key": "8C05F37E25BBE33BFAD40E3BFFB4EFC1", + "v1_mic_short_salt_identity_token_hmac_key": "5E3DC31AF514DBE21286E86009435844BD96CC31F501B48E0CDCFCE0032D42AA", + "v1_mic_short_salt_mic_hmac_key": "41C70F6FE4E862553196A69B4B66E32B15384159A6865464EB50824E1AC399DB", + "v1_signature_identity_token_hmac_key": "7885A9B7E84FB130334AD9AB8BFF1643B3D33D68DE2CD208977656EB5CADA2EE", + "v1_signature_section_aes_key": "D559EC95E7D9D905C43582B528204FE6" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "D1C8", + "expanded_salt": "ECCA8A1F9E8E75DCF570C5D713300889" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "817052592ED2AC889E53F3DB", - "extended_signed_metadata_key_hmac_key": "ED836D0F732D1051DD4E7DAE505FFB670CA6717F7BC287E0C8957EEAA6AAB9EC", - "extended_signed_section_aes_key": "03D31EED691F220ED807A0A3699D01E5", - "extended_unsigned_metadata_key_hmac_key": "0C304D6EA35B6602646FC0E6951EFF09249712E42E8AA6BD995666AC29E774B6", - "extended_unsigned_section_aes_key": "8507DF1A8D34390EE03C10C29C16E20C", - "extended_unsigned_section_mic_hmac_key": "857FA3CEE51F9018367961FF82F30041D43DB1F1916BF067396EE7DEEE08B063", - "key_seed": "F7E47754ED974913367ECC4B4DE2B1E66D9C8EF36BC36875111231A421A1F892", - "legacy_ldt_key": "DF739460333EED047E4700C6D43763208D6F7B8994CD36AFA6C3B725124BD68F50A5DF542D16780F8FAA64C919F4E1321752C2473BF44843012F49CCD2BDC43F", - "legacy_metadata_key_hmac_key": "7BC61FACD5C01C6F0B24B38004BD8CC5BD00215D9270D8621919266CFC7CC1F5", - "legacy_metadata_nonce": "23DE6EA7BB73D686CA04432D" + "v0_identity_token_hkdf": { + "expanded_key": "4A7142998A8FC059C0EAFB18E6939785", + "v0_identity_token": "BFB0CE297F64B3AB7557113C54AF" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "FD97", - "expanded_salt": "AB621F612EC9F1DBF995C1CE7610A3F4" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "EE43", + "short_salt_nonce": "FC424C642B26FDAE820AF1AB" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "7E59495C2E31ACF37A8A82914D67A3C2", - "legacy_metadata_key": "FD95D8D7F1234F29C61B73586E50" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "F352BAC3D04AAB1663A78964ACD27F3D", + "derived_salt_nonce": "BEB93BCF36574D428781A04841770194", + "derived_salt_third_de": "21E4F9FB37F092DD846235297297FBED", + "section_extended_salt": "A20F1A436E3CD07AF356935EA412F986" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "B1FFFDB5149EB2C1E55818C9AC278F22", - "derived_salt_first_section_no_de": "9FF7BA7CA2D7A64907CAD503C9D9E931", - "derived_salt_first_section_third_de": "E05CE47FEAAB471BDAAEEFE326144F87", - "section_salt": "05FD6AD5FB6ECEF67187AB22628D83F5" + "key_seed_hkdf": { + "key_seed": "EE6C12A309C3D379106949857A2CB8736DBF31E30D519B8CA103DE0C67D702BB", + "v0_identity_token_hmac_key": "FC9E1DCF166C57CEA1D88205FA013353A8A5C92919224E4CC4C05E4EFD81BF78", + "v0_ldt_key": "7898406C1F2E86046C179E417C18B2C78414A95C5E1993271CB5E731F13D0A05B8F31E71A81B9A0A323C4841EACEAEFBE026CF0BEA6DE5661A2B671E4F89F786", + "v0_metadata_nonce": "4DB6DBED980D2BE700FC04FC", + "v1_metadata_nonce": "78FC55E3F54D576A0EA7DFE6", + "v1_mic_extended_salt_aes_key": "45C0F33938366922940EFE7E7097C261", + "v1_mic_extended_salt_identity_token_hmac_key": "7697143041920B2E9561C1414E72CC0E55FE65C46E13952EA0BECD995799D52B", + "v1_mic_extended_salt_mic_hmac_key": "DD85470E8F3EDAF23FE25157B8FBD1A7C241E7B1C31EC2A198F345D750D57A32", + "v1_mic_short_salt_aes_key": "88A8BC6F73692B9E4BA3D932F34A1C12", + "v1_mic_short_salt_identity_token_hmac_key": "06E05118607B678C75BE26876B469D29C7E039EA5BF642B2339CA4D30EFF432F", + "v1_mic_short_salt_mic_hmac_key": "B24E520B572C5A64C652D5F7E95A58FD937569779213CD79DD435503B05F8678", + "v1_signature_identity_token_hmac_key": "F75DDF545736C151BD76F0AF6D952DF525D7F53F0393F42346B6DE51D410F6F8", + "v1_signature_section_aes_key": "972451D672CCDB9E7CA5D68C7CA291CD" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "AA55", + "expanded_salt": "A2A7A96222BBB587E385B4B0438837C3" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "656ECAFAD9D02F5C53D1499C", - "extended_signed_metadata_key_hmac_key": "3C07733D5EADB798C0F0A085711E7980D5437BC8D9003F2E6D32EB1E997D8D08", - "extended_signed_section_aes_key": "D49EF1EFFE0236EA082EF79C6BEF496E", - "extended_unsigned_metadata_key_hmac_key": "BBAF91442DABA83EAEA9AA3C6312972672AB20FE962605FDD01FD709F832D562", - "extended_unsigned_section_aes_key": "D472A600CD6F77F233D6274917328EDE", - "extended_unsigned_section_mic_hmac_key": "62A45AFFBCAE257E682BCB364B77F8FFFEF9088BB8DE260FAA6E622088E44A43", - "key_seed": "744EE5E68214D686A678E2F964A33C054EBF0155354CEEEC0EE77448F6E156F1", - "legacy_ldt_key": "A3F256081813BAEF903C9DC155AAAA8F7D8443726E1DB42695632D36BA9932E0A70D568A10CC1631D1CCB86AABA44B82CE08A65EB31C466C4E41728A11429BA0", - "legacy_metadata_key_hmac_key": "33EADD4558505A6805581DC7E514C624670C824B489D63F54500E7AE348184E4", - "legacy_metadata_nonce": "33283F73B1E3EBA32C5D862D" + "v0_identity_token_hkdf": { + "expanded_key": "D181D62BE2814F8A4515CEE9F98CB16D", + "v0_identity_token": "82AAD91558602B7E975108E4C1A8" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5987", - "expanded_salt": "BDA17AF3C8D8E8E7627742B3AB2075B6" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "1692", + "short_salt_nonce": "41FC0F8BC4B6ADD56E767CA0" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "F9BFA683C1B856991A2C5CA893D71050", - "legacy_metadata_key": "DCE4D724E5161B46AC54E4C18A08" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "8CA3B5B9AD5A244C7C81A4CECDFBA881", + "derived_salt_nonce": "B19D427E9CB92F7F2D1F433BBFC1C484", + "derived_salt_third_de": "5EE54CE1EE6359617F847ACF515237C4", + "section_extended_salt": "05FE726BE045EDBE53C924C94DCC01FF" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "DB22BC19A27CCC15E51A0A1B950857F7", - "derived_salt_first_section_no_de": "547CC56DC0A5507125082C68C053D5D5", - "derived_salt_first_section_third_de": "DFBAFDA1CF3AA59B26FE011EA450B823", - "section_salt": "078A2C255BB03030F52965D13B0AA53D" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "1020F8C375AC5BF5D3DAC380", - "extended_signed_metadata_key_hmac_key": "98F6FD73D248D52E1338E6F37EF4BE53160EB68C57687BBD5F4C4AE7F2C5A6CD", - "extended_signed_section_aes_key": "63B0CB478D4E5F38F454521A785B5DA1", - "extended_unsigned_metadata_key_hmac_key": "77A743C542941356A1DB8D8F3031439401B82F1B7A6C5BDA68152C1232603CE9", - "extended_unsigned_section_aes_key": "B743EB7D63164D30EEA5F452F4ECB6EF", - "extended_unsigned_section_mic_hmac_key": "F34F5FED159362C0CFCE08702216F77B7BC9BD6739D7B7A6BE022F69E119A011", - "key_seed": "8D8B909F903746E317D2FAD7B81C44E14C2BC911BF57505FD21E657BDE7B9448", - "legacy_ldt_key": "B95B352CC7A616CFCEF94F140DB1FFF6C96699456B53E22EF2A92C189C8ACF71B15996E5592651FDB0B9EF482E3D3A77F69C43381BFA3FBEB77EF3FF3508C4F6", - "legacy_metadata_key_hmac_key": "0FA59F92E4D45EA6F7CE221654D40FD7F04723C271B02CF2E6FE7D2F38B1F9C8", - "legacy_metadata_nonce": "B8CE49F04135E2EFADD82878" + "key_seed": "04CB72E32403D848909CD752FB1728D044B0B922E11933AF485BA6667BDA8095", + "v0_identity_token_hmac_key": "AE509065FAB5D2F92D5879A79367774D0DD1E299592700BAEEFF59BB38EF0F7C", + "v0_ldt_key": "EB2A03CFB458D8EFDC34F5A1C295CE89A7E4C16EB0A310EB29FFB22C058BC8EDC12679CBB59184A1DAC8914A3266B7DA4A9A18DBC463DDF0F1188E6A1D937317", + "v0_metadata_nonce": "F8C6BD75CBFD3563E67C738A", + "v1_metadata_nonce": "868F99953CEB467B28C252A1", + "v1_mic_extended_salt_aes_key": "8DCD6EB583FC8D6A09D0A6E4887C0CB7", + "v1_mic_extended_salt_identity_token_hmac_key": "D379FCA209D85EE044A08DC891E4F0E54A46346D5E6E47B28C213ADF81246750", + "v1_mic_extended_salt_mic_hmac_key": "F7F9A514455AE831234376BDFBC64A3639D7E2C4274851EBCB7EFB14D3392FD7", + "v1_mic_short_salt_aes_key": "2385AEC92C92345F560C4D292D3C4C98", + "v1_mic_short_salt_identity_token_hmac_key": "45B7159DC874A72B0F232DB37EEABFC00B801453BBE78B57A5C08B2FB8AE626A", + "v1_mic_short_salt_mic_hmac_key": "0352B8CEE18F5D2A75B5D055806611BEF436A2F2172447236E6C929B41C00FF5", + "v1_signature_identity_token_hmac_key": "789B7C2BBEA40F1E9D8C35CA4F6A80734F4A0EC11973F49EEA988DAC0EF10877", + "v1_signature_section_aes_key": "9AE1BC3E1532FC968486276BE96AEB6C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "E04C", - "expanded_salt": "C09ED0239B32A0C2BE3A0EE440CCBE42" + "v0_adv_salt_hkdf": { + "adv_salt": "0733", + "expanded_salt": "5F072B4BB16C2439CF35176A4E208D43" + }, + "v0_identity_token_hkdf": { + "expanded_key": "DAE265F7391FF6871E5BF1A60EE33F1B", + "v0_identity_token": "29E46351DACECB436710E7BE3CFF" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "89B6", + "short_salt_nonce": "4B223F4BE10514D1B8407002" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "3FEE720404CE1EA1B1D761262F6E2C09", - "legacy_metadata_key": "5D81EB7355CC5ED9A8979ACB3DC3" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "4BF6F87B0CD12A0AE66AB6C80C976E33", + "derived_salt_nonce": "3AFAF9158C6986EC11F22D14ECD21D29", + "derived_salt_third_de": "EF28C13335BB6321FAB46EF2A859DD58", + "section_extended_salt": "0DB9FC8CF99C093927DFE9CC092C008D" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "0062A464AD7B46EC51A8083B2F34410E", - "derived_salt_first_section_no_de": "08E8417B389B48DF971A62A738A28A1A", - "derived_salt_first_section_third_de": "A475206446E694B5751C5E3CAD225454", - "section_salt": "F2F39B46ED2763C2D2471485E6EAE97F" + "key_seed_hkdf": { + "key_seed": "278BA457B88F328447ACC1E6A4E14BE7A62A44CABF28330D6DC044050DF55085", + "v0_identity_token_hmac_key": "6503711E003223721BC7A3412B7387FA2BBA963EB581D1D60B5A17BA0E7C4B8E", + "v0_ldt_key": "B6FC809AA5F0DBD46A75F6639594D74B5831293824AB4A9922997A3B3A1E6B12111084BE521B3A486E16DBE1AC0FCB346AE16FEC6B80E3560419AA616CE4984F", + "v0_metadata_nonce": "67CABDAF41792AED8A72A868", + "v1_metadata_nonce": "8B6B23B4E69766931BE22DEC", + "v1_mic_extended_salt_aes_key": "9C86645E9BCE74A1EC73AADCD665154B", + "v1_mic_extended_salt_identity_token_hmac_key": "1632B567AC6144C41081C91C3F5BAD0B560F59602E39FD0B6207BB5DECF7D734", + "v1_mic_extended_salt_mic_hmac_key": "8CB11E1B229A46BF2620483B959201465A44A31F6FB9E675539B7F27439C8B0E", + "v1_mic_short_salt_aes_key": "2C9851D5CD39BB2E1FEC593F79F23085", + "v1_mic_short_salt_identity_token_hmac_key": "70315F0D044A3F478184A76892BB4204A5CC1E4542CDA99595196323C0770B31", + "v1_mic_short_salt_mic_hmac_key": "FCAD5AB2AF31EC2C2649B9DEFFCCA9865B74E332E81474E8FBD7356D33F88DE6", + "v1_signature_identity_token_hmac_key": "80F9B9285D8DBF0666839F92E2D2752EF249FCB127503BFF41A629DFFAA1CB45", + "v1_signature_section_aes_key": "B519FDA43EE7B072ACB8A855A0820016" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "0F09", + "expanded_salt": "8ADD04F894BD7DED3AA47EC0A5AA2F98" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "9D465DB8703FD644B14B99E1", - "extended_signed_metadata_key_hmac_key": "14BA9DEE1626741059F8B6D426CF83FCE010C26124E5AC9D66925D3B89EE2BB1", - "extended_signed_section_aes_key": "591995C12F75A6D28673E9BA651BF099", - "extended_unsigned_metadata_key_hmac_key": "7BCCE36CAE2D834C397513EA6C8F90026A1108A856285F9106B38319EFC9FF9C", - "extended_unsigned_section_aes_key": "A5A156C9EC17E50D3D4D5DABB63CCBA7", - "extended_unsigned_section_mic_hmac_key": "EBCEE2B687E58DD608CA3BE824C5465BB325FF602E30DAEBB2F2544DAABEF580", - "key_seed": "6EF7F1684C5C353B4ECDB1EEFDC10C34CF78B9E60D067EC7DB769595F8914CD8", - "legacy_ldt_key": "8251C9BC73D421AE9345E27335D84A03BB706EE9A2ED41A90D3E7BE66B3EEE9D98ADDF2958DD85B21FF1BF5CB06DD1B7180781BC89EA0AC6B31E0DFA8B6F49BA", - "legacy_metadata_key_hmac_key": "177B5056A2BF6ADE707EC448CE3825FC7F4EEFBF6118F58BAFB9504B461FB3C0", - "legacy_metadata_nonce": "989E60F047E8D4BD15075FDA" + "v0_identity_token_hkdf": { + "expanded_key": "CFEBF4005115348238072AB6881A36EA", + "v0_identity_token": "818BBE9BBAD25F7622319DA42806" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "0E4A", - "expanded_salt": "45841BEF518D55BC872449D35B69D3D3" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "EE7F", + "short_salt_nonce": "C2DA1EC8766C69498CB6EB47" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "07BE6AE936B1ED68B3823A6893702467", - "legacy_metadata_key": "0C15537A85CACDC26F26019ED439" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "E732FDC269D45C4213635D2D35B4A8C1", + "derived_salt_nonce": "FF25222D3D493186CBEA2C203733BA86", + "derived_salt_third_de": "02BD9E3B04444BF78D059BB4336D1D14", + "section_extended_salt": "BF79E23A91CD05105EDB13CCE3CB6B16" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "3DE9D56F37147C866D25DF4D1EC6E854", - "derived_salt_first_section_no_de": "2FDE5B60AFED59C1CF366A514FBBACA3", - "derived_salt_first_section_third_de": "AF10E5F3A5DF61DE19420E75E55D12BD", - "section_salt": "ED4025D9A2CBE10CAA5B8A1ABA910BE4" + "key_seed_hkdf": { + "key_seed": "477C882082527F23F504FBEFD21A679EF0409EA198BC392C5113DEA2755DF924", + "v0_identity_token_hmac_key": "196C59DDFB9139C0DDBC7FAB56AA600DFDA39EFE683DB66529002A7E383EFC64", + "v0_ldt_key": "A1F7AFF1BC0D85F14DB34C40A82A0DBD75179F7F164958602E6859D281A872EB7C979F1D09C29D1D5F0C89805473B7FD28B5269E52B220AFFAE81C77619FFC7A", + "v0_metadata_nonce": "FA10FEE70CFECEF59CC0E0E0", + "v1_metadata_nonce": "1E02CDDF1094116A322052F1", + "v1_mic_extended_salt_aes_key": "3FC29BAF9D68FBF0312A6642360E7BD1", + "v1_mic_extended_salt_identity_token_hmac_key": "C4F0AEC099DEEB16FCAA31731CE8C3C4B480EADEE65EA59DADA666BF558DD945", + "v1_mic_extended_salt_mic_hmac_key": "73494C1A3BF1D355985E61D009736941FFB39A3251D915D7EB3E555E887117BA", + "v1_mic_short_salt_aes_key": "622187A9DC8AF81E033888DDFE504F77", + "v1_mic_short_salt_identity_token_hmac_key": "0BD43C55C16C95BDA2A6DFF39A9FCAE21CDF87DE842C35694698B2B53D1FDFAE", + "v1_mic_short_salt_mic_hmac_key": "9900746A6567048FAC292563E40333B948F5D3EDA89BB8D8E5B159441D5EECE6", + "v1_signature_identity_token_hmac_key": "9A2793927FD494FB1AFB2EB7F7B91319A231EC88B1A22B3E42293FC1EE81E388", + "v1_signature_section_aes_key": "0F5A12959E5210EC994C97724D3E2A96" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "2B8A", + "expanded_salt": "F4FA10F6983E9EC4A7F916E5FE7191FD" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "6F59318B12B620600E40892E", - "extended_signed_metadata_key_hmac_key": "383DEB0C8AA51D119AF01606930A19F42C253BA8AB6A6CA730F7F0DA67F6526B", - "extended_signed_section_aes_key": "8E2158CCE463C86814C3A923EB66BAAC", - "extended_unsigned_metadata_key_hmac_key": "551F2045C860E1A7B7B0E190ABB6A51447E9DBE9009AFC46FECD25331E4AA414", - "extended_unsigned_section_aes_key": "8AEF9D42C27067B232BEA8242FE93F3D", - "extended_unsigned_section_mic_hmac_key": "788130EA49F3BC5C2D9FEBA9C9758A4B268A0FB16C2B844A4F28E03E7549D602", - "key_seed": "0C692A79213891396CD3B92C3FAC2DA33EB0491272E59411E1CCBAD01F1CC663", - "legacy_ldt_key": "AEBD9A429EF5E38A23C12F825C269950D231BBC7548115E198C7BE64B096B6FA6C11CB120803241FFDE8A78BACF27CE5545DFE3E896F598CB5EA715115B9EE56", - "legacy_metadata_key_hmac_key": "D68DC293B640E8E6E0E60DAA01B744FB59FC2EF5868D8856EBDB39772A510E5A", - "legacy_metadata_nonce": "EC688179F89D775E64394EC6" + "v0_identity_token_hkdf": { + "expanded_key": "427F95E0A764088384200A097E6AC5CF", + "v0_identity_token": "FC6827BE9D955A04B5D4DF33849C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "BD8B", - "expanded_salt": "F3078BA520F2080B927ADF89CF273A18" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "8EBE", + "short_salt_nonce": "2183C1252F128A480A53CCDF" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "DDACF0C5D556F78DE46253E77A85ACFF", - "legacy_metadata_key": "9732F406F870342BEE8B0A914078" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "1033FF7BE57DFD280D3F1AAF407831C0", + "derived_salt_nonce": "E6D9C880D2182F448A6615F7FE10BE69", + "derived_salt_third_de": "63A9C49B9F470EA354637612725729A0", + "section_extended_salt": "9AFB8618127F357D0060618E781CA599" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "EB86DD1685C8017EAACF542B7A32C154", - "derived_salt_first_section_no_de": "2E1D91452B6BE755CA6D1A510B786F95", - "derived_salt_first_section_third_de": "3F6795CB4E05C03486FBAD12D98543FF", - "section_salt": "700111649D792ABCC1E004978C637E0E" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "E3A2F71B15300A7232927D5B", - "extended_signed_metadata_key_hmac_key": "688536A171F65ED7AF6DBE841968025720997891374D0E30EAD96C2DBA1C6CD8", - "extended_signed_section_aes_key": "72B7CD1147CAD43C239D0637C9192967", - "extended_unsigned_metadata_key_hmac_key": "22EFB24D7DEE84A07643AFF3D11A0EF56D818466C43882E3170027DE0CBEF920", - "extended_unsigned_section_aes_key": "C38BC169874FB5551DEA99A853A3242C", - "extended_unsigned_section_mic_hmac_key": "28F8743A05F77BB067BE29BB714EF5208532383125EB35317F6C9B464E65159B", - "key_seed": "8062D40BA07D2331C15DB4F4992D45A4C500350EB2B4DE00BF5EBBCE396A96E7", - "legacy_ldt_key": "4ABC6C92EEAAA16D277812A851D8A1334846D9FDA1DCCAEEA24927F74765F37C48FB6297F88982234DA5B576A6FA5EA69D11972104350CC3CD20932799E3EFDC", - "legacy_metadata_key_hmac_key": "30121B3A3B523BCD071DECE2F469E96D24EBD5B83CA941EAF7F038010A70A1B1", - "legacy_metadata_nonce": "873248D5319D71CF756CD8B6" + "key_seed": "CCB8E6B8AD20D8B150E8FC97A098B6DDD7C1997701EA879CA64182B22FA55503", + "v0_identity_token_hmac_key": "E1BE3B3F12B2A2182B49983B8068BA6FA9FB3DE509D671816BBE008523818F8D", + "v0_ldt_key": "0F2B30FB50E701F0DB08D85F0CD7328E577CFF43EDB6B223928CB2258BCF1E394E58FECB9596D2AC6B8D43947C4D175BEB95548F21301E1F1F733934393A7360", + "v0_metadata_nonce": "942ADD1379EE90A6DED3B65D", + "v1_metadata_nonce": "4CEE030F946DF65BBB885DDE", + "v1_mic_extended_salt_aes_key": "A1BED5A13B44D10460EEAFB4412EE475", + "v1_mic_extended_salt_identity_token_hmac_key": "19675B5C73515ED298ECA658901F187D321A83C935A15C4D4A4844DC48BF077F", + "v1_mic_extended_salt_mic_hmac_key": "5D193196A34E4437DB7034795266C7C62DA3605D9F5818C2D433292E610A3762", + "v1_mic_short_salt_aes_key": "B29FFF8F001C4726749A2FE7047A82D1", + "v1_mic_short_salt_identity_token_hmac_key": "F1A90E829ED67B49C445D7DEBDAFC88E3BCF1974F0ED1EB9643730BF6EB3B90D", + "v1_mic_short_salt_mic_hmac_key": "BAB6DA7601191FDEB4344FAA163E818C9BF9B1D5B0AB1EE8D9F4A1C1D30A86E7", + "v1_signature_identity_token_hmac_key": "8C6832DB6955803AB934B98378B7F81F3710C65947A8B2C6132525B163F62CD6", + "v1_signature_section_aes_key": "8916CE7332C1F924DCC17E68D999EE7D" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2D7F", - "expanded_salt": "3C48F27B1F13EE4BD87F817785EF7703" + "v0_adv_salt_hkdf": { + "adv_salt": "C270", + "expanded_salt": "3CD8235D88B0B4D1A0236DCCD0F5629F" + }, + "v0_identity_token_hkdf": { + "expanded_key": "8DBCA7616260D0E347D3984DCAD03372", + "v0_identity_token": "D02797D4E963A7B9806E5EFE0FA0" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "C61C", + "short_salt_nonce": "7803F0E069FF172CCF47AA05" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "50979493AC77E7C48BABD922BBBF9775", - "legacy_metadata_key": "EC8D649AF82B50E56F7E5F2C1426" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "6D93C32275239B6A82508FEFDFEC112A", + "derived_salt_nonce": "D2C45BD5079FE6B2D69E4F5EA192CE07", + "derived_salt_third_de": "2CF3FE0C1E6689361B50D2B558FCA09B", + "section_extended_salt": "23FF70E4526E9961792744D2C7534BFE" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "D262A02E3A58DF486E345BEC4A2B5D4F", - "derived_salt_first_section_no_de": "9E106096FF44973E527F2F7CBBB68275", - "derived_salt_first_section_third_de": "F9B9F4D9CBCB69C7A00DA254229D4BF3", - "section_salt": "4496838ABE23AA21C0CA736114A37BD6" + "key_seed_hkdf": { + "key_seed": "9617CCA86C2DE55751298C2F0652DA17D9C461672AF0B25F4440ED17F9A17768", + "v0_identity_token_hmac_key": "C4FF34211E8D5C43FBAF8D6653A8AF5FA760F13459000F70082B9D143F3975BD", + "v0_ldt_key": "9A118827A019C5EFD3FC97CCC3B10F74C15D56126669EABE07317EC7A02B7B0BF2021383D3F48DDAFC1AEEF5AC930304BE2C85128AE2DF0F6F679B8D48E5CCCD", + "v0_metadata_nonce": "A9A2B6059169FBBB81991A3D", + "v1_metadata_nonce": "F6B42D5761F30BA937AB8B7C", + "v1_mic_extended_salt_aes_key": "328DB3BB74879515324035839561552B", + "v1_mic_extended_salt_identity_token_hmac_key": "36243F4E25B1548560477EF30CEB9A785C49D244832564BA262596735ED2DC1D", + "v1_mic_extended_salt_mic_hmac_key": "693EB813C40F33650699205BD038EC0D09989F8BA0A6B50741EC8FE1211DFDFE", + "v1_mic_short_salt_aes_key": "ADCB2F8D667D5DBABAACD28F72C2E11D", + "v1_mic_short_salt_identity_token_hmac_key": "0501458FF851D1C3C83C1BB65F55495E75C24778AA9B8FF0488FFB7F119B574E", + "v1_mic_short_salt_mic_hmac_key": "2ABF2E7A68FC09E88AC1122710BC7DD9F57FB8E150F699D5DC0DA5A560C76044", + "v1_signature_identity_token_hmac_key": "A267DB5025D3F87D12966C3853FB9449AE1FC4B654428CFAD44AB3AF6020D572", + "v1_signature_section_aes_key": "9E6F27E4E0118B8507146871CCF84E2B" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "81AB", + "expanded_salt": "F19E33C05E6D989BAB7EDE336BDC01BC" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "786176FCFF3231D1572CA808", - "extended_signed_metadata_key_hmac_key": "18CE44A7087E1E3FEDAA6248262F697E1BAC68F878815DDF44A330BFF19A43ED", - "extended_signed_section_aes_key": "AC9B94AC20F1D81E1D1DEC0684E36297", - "extended_unsigned_metadata_key_hmac_key": "47C8F715E8E2E9F67B1C376E2D726A60D30D1B8033E2D78B7EA3D1DD55BA23FE", - "extended_unsigned_section_aes_key": "0C40C4BA4105CE4F2CBE9C8DE5F01123", - "extended_unsigned_section_mic_hmac_key": "6D9373A7A34B9072FA386B06725B4BEF851EEEE601907991C5D2D51500356F2E", - "key_seed": "EA366AAA629102AB6B62305B92BFF85C878A1E7536C2057444C989AA68370138", - "legacy_ldt_key": "4FEC3FF94C7E7BBB8A7ADB496EE01056B702AD1EFE5458E94FD0D9436EE976CB367F12FF19A31166D2E7541C7C71C1B3BF25E532B08D80A456A1FF04A6C79503", - "legacy_metadata_key_hmac_key": "EF0679E429D9B23036DBE7B8AB08AD5B02C236DC8C2D526EF3E0E840E1FAE6FE", - "legacy_metadata_nonce": "B90108EF65B54923459A2B9F" + "v0_identity_token_hkdf": { + "expanded_key": "68B06A0E1A66F6B996474EE0B282718A", + "v0_identity_token": "F60E36A8E0605B46D6A05871C90C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "5203", - "expanded_salt": "A3A47B0B38AB2899441F905548251625" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "A80C", + "short_salt_nonce": "8F039D3FA934BC8560918D45" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "BB0BAE62AFF2FE5A6E20B8D581A272DE", - "legacy_metadata_key": "DF9B54563110C3D424C36C7A0B12" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "FC34E69B7FA34B4341D2D33D5D591D46", + "derived_salt_nonce": "9BF73251EFD5E11020390188ADFF72C6", + "derived_salt_third_de": "C80634B6E96C0D7EA25C5C47F7389B01", + "section_extended_salt": "DF9DAD95D8384321FED7873DFC750B66" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "9794C1A08CF2F8E1E64FC53A89C81798", - "derived_salt_first_section_no_de": "899E09BEA7E181371FC7DB3E064B93BC", - "derived_salt_first_section_third_de": "BDA3B1732F5E0E7F2D0E8F3EA79402FD", - "section_salt": "82CF94C9A74170CDB84C8132E0A9AA25" + "key_seed_hkdf": { + "key_seed": "E465DD783C41093B0A855D11D3D65C141C01A27D0522D7049AC8D92CBEB9D232", + "v0_identity_token_hmac_key": "9700E177127FBFC6271A4E7ADE829E5D6BC19901DE311C66F0D5283475241C23", + "v0_ldt_key": "FF929D036F9D8713CCAFD13A9A8E3EB1368F904BB28C3A5B16155D440245F2F736A885306539CE9DAE5E8E1E6915738FE2300523831F2FB284A858D968ACF2EB", + "v0_metadata_nonce": "113FB8326CCC81FE306E3722", + "v1_metadata_nonce": "A1B0C6917739A95F4E36EF34", + "v1_mic_extended_salt_aes_key": "FD52721D70BAA377D20F679583CBB776", + "v1_mic_extended_salt_identity_token_hmac_key": "C384F651302B7D322F5E3F8A2694A49DF03034C0A13C0A827250DE10E9708B01", + "v1_mic_extended_salt_mic_hmac_key": "DD1077C4A05C4701B7EE34561CCC9D4D46C80E522414CC1053A2A3C3F918E24E", + "v1_mic_short_salt_aes_key": "EBDF2DEB57C82EC7633A337346495321", + "v1_mic_short_salt_identity_token_hmac_key": "B5A4831B58E71C5EDF3206D25CD378D2E569EC32E8E10E173C82527AF7DE59E5", + "v1_mic_short_salt_mic_hmac_key": "FD94C8A62DD00C251DAD6ED9DC459E1C06C2E625C24D3EA902122BE1B1EAFC13", + "v1_signature_identity_token_hmac_key": "40BACB42A697D9B7322FFC8196CCE5ADCA84758196F9211572C51D1E96683536", + "v1_signature_section_aes_key": "ECC4297E2036A147E17C48550B32C9C6" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "D77E", + "expanded_salt": "7224B61774E1B0F193E6E2B9C6828D47" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "9E2E62CFF064E5688C2B785E", - "extended_signed_metadata_key_hmac_key": "397D11E6EE958656F2674EF69001146BEE0F972C497C92C71914B90F908228F7", - "extended_signed_section_aes_key": "C5AB5145752AA16E3C65C6EFE561EC9C", - "extended_unsigned_metadata_key_hmac_key": "EAB5C3F841C81AE3394987D3AE876D5043778BB711A191C36BBCCEF42CA3FF6A", - "extended_unsigned_section_aes_key": "E9B70118BF8A4D58A758F1B3FA1661AC", - "extended_unsigned_section_mic_hmac_key": "B3E6D61C78A8867BDD3F33404218279D13F6F89059671DED0E8D4EE34C7FB5D2", - "key_seed": "F61539C310341BFDA73F7D9504502B785A27BD555E2A4B80BCE329AB213522D0", - "legacy_ldt_key": "2D427E218733944B5F784EBE48E0DA05A515BE4D4D6C56FF79E36661F2DDDD8D6ACEB11FBB0F7C9DFA18EABF0BB2FA96F093F0D599DBFE357265DC5A6C860ECB", - "legacy_metadata_key_hmac_key": "53DB1506A87A258744C9B065C1B6D0C39395EFA8F0E6C543415506BFD6252FE0", - "legacy_metadata_nonce": "D3B81B8D52920BB3D47EC5BD" + "v0_identity_token_hkdf": { + "expanded_key": "29AF30ED417C4F170B58DABA018BCB99", + "v0_identity_token": "F0663FB846121698C69430BACA77" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "2037", - "expanded_salt": "E1430F688FBB46C8F6067E50A1F4B296" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "0C83", + "short_salt_nonce": "DFDD3C550621ED62C9452D36" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "1D4C9F7C2CE767CDAAF1F2E2CC9E56D4", - "legacy_metadata_key": "8A521A8E6FD14285498B5DEC2A79" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "CF6F2269AE6601323D59347A6B698B6E", + "derived_salt_nonce": "8E899705639BD06B26439FA131EE2A2C", + "derived_salt_third_de": "B00A28308187B862E7F971387CA44CC4", + "section_extended_salt": "B543154433E370E6D7A97B46A73F5652" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "4363CB3C7259246F4B123095550EE704", - "derived_salt_first_section_no_de": "6E95B9CFB044108DE5EABDDD098667A4", - "derived_salt_first_section_third_de": "F4441684E3A1C584AE218220C5823D63", - "section_salt": "4FB82CF0A6F46347DE465EF01BEF9DC7" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "7F8B9AF9663AE92297910F2F", - "extended_signed_metadata_key_hmac_key": "12328EBBAC73837BAC2D4B82D2EB0943C41F11DEA46B6562C1992B49F91D78F4", - "extended_signed_section_aes_key": "DB11AC0C3FBD6B105EB4ECF65440F2BF", - "extended_unsigned_metadata_key_hmac_key": "D8A37BEB7EC0DB54ABEA9C4A05616090ADE42C3C255949698690C5D38D683627", - "extended_unsigned_section_aes_key": "AF42DDA012ADF8A795EE4A7B15DAA081", - "extended_unsigned_section_mic_hmac_key": "48EA765212AD49D3527D56554149629C969AE888F1D681DEAFE78CB0F0EAF658", - "key_seed": "E615EDD2FD82BB47855C4BE869BFC649E0BD0EF7A15EB0C8F99E5884156711DB", - "legacy_ldt_key": "EBC006F8343DAC70202A8ACA714C41EDCFBC6B5A5E6756DE2687A2A2B02068CF3317F3083E0DC3D626BCA08DFC188F1FA131B90679899618782C58CE2D3416E5", - "legacy_metadata_key_hmac_key": "F50BB9D2761D9FF880911989A82C2B844E21D7F4AFEAEA1CDB5F8BEB417F1EE0", - "legacy_metadata_nonce": "9152D3FCAB6D25F3EB847E41" + "key_seed": "882D400EB39A85F33D277BF925D7ED0E552D94A12BD15AD17F7151FE69E775F0", + "v0_identity_token_hmac_key": "1A0D3CFA718CBBDB2B330D38803A1BF03DD759B1EF1C9C0FDEA869012F89958A", + "v0_ldt_key": "9AF4D1867CF679CC66E3E874AF8056FAC8173B2287DB6CA871D6C3AADA33F936E281AFC6C09E0DBD9E16B067623763A66F0E5584028C36300D972D39E0C1C71E", + "v0_metadata_nonce": "96CCAE0B699F6A861C2FD9ED", + "v1_metadata_nonce": "475822C913CF03C67FDB558D", + "v1_mic_extended_salt_aes_key": "566FC52F26306B98BD4F702D783CFE18", + "v1_mic_extended_salt_identity_token_hmac_key": "B9E518A687FB1E222F2131F9D730493C7BB78E92002CF782FD30C75272E24B92", + "v1_mic_extended_salt_mic_hmac_key": "893E8AFB307BF4C011CDA36140152CF892F2356DCB8B87AB8D3B0CEFAE7D23CB", + "v1_mic_short_salt_aes_key": "33EB408FAD37D1FF76A27B2CF7D421F8", + "v1_mic_short_salt_identity_token_hmac_key": "9EEE04B64C468770682AF45F96D7DCA1D6EF53D4C592A2AE7A172A0DEBF10E21", + "v1_mic_short_salt_mic_hmac_key": "74655FA0D30D1E2DF0DA9747A3966C9111693B8E00704DC61D2156009D9F26BD", + "v1_signature_identity_token_hmac_key": "801294C7CA501C3BF20F57BA2B0E2FA09F13722B3655F625AE8E17C8A79B1154", + "v1_signature_section_aes_key": "44D3F5A168DD048901D7FDA07952634C" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "889B", - "expanded_salt": "7FBF8613F21C47797F4814D1939629E4" + "v0_adv_salt_hkdf": { + "adv_salt": "ADEB", + "expanded_salt": "E005DF91854CE6AB6186D3C976110C49" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "B10610105C6FB841987ED5DA28B1A8FA", - "legacy_metadata_key": "82558AF0C2A123C0577AD47FDDD9" + "v0_identity_token_hkdf": { + "expanded_key": "8032E7A696CC593BA7863159E0C0EA10", + "v0_identity_token": "460240DEB4C8813AA5815BB6E5A9" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "4039", + "short_salt_nonce": "A4E6F88E3225FACE356BFDA4" + }, + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "3885509BA1045121AE5CED396AA039EA", + "derived_salt_nonce": "679DF301EEF3F51C43FFC1701A184685", + "derived_salt_third_de": "441CDFC937345A037284C3E35698448A", + "section_extended_salt": "B43C581ACFC8A74540852A7DC924867C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "BF63189D3C53D46BC6D15EA10B4AB4E0", - "derived_salt_first_section_no_de": "C2D485579DD258D6806CF6E345E0EC22", - "derived_salt_first_section_third_de": "1CCCCF350FD11768168AC0C94F598931", - "section_salt": "3EE85997BA02AB4A6620B2CE05469FE2" + "key_seed_hkdf": { + "key_seed": "408039A7989CE0B9DF3D3BF66AC9400458A14B524EA03CE24C783D7CEEA6130E", + "v0_identity_token_hmac_key": "09DB35D01A5476F41E66061C7420136EA7100245C979987C91111DAFDF5122E3", + "v0_ldt_key": "24A79BBB1033112612B3F710B6A9052548CB75772ED0AB03613B84EA77989879032C8026AE28C45D46E71E19261F454C7E0C2A48C8813CBA0D00A986340B31ED", + "v0_metadata_nonce": "7D489586FA49BE4CA0B5A333", + "v1_metadata_nonce": "F89E50CC26C5A4185A97A407", + "v1_mic_extended_salt_aes_key": "4A8884EFFAEFC7981A95DF8A76C68D0C", + "v1_mic_extended_salt_identity_token_hmac_key": "5712CAD3673FCB0E83E0BB52AF7D23E84C89D79F9526757F2B5070CA9D9DF81C", + "v1_mic_extended_salt_mic_hmac_key": "DB771C4FBA0936936876181EDB642A4C3C018561845F35B3D0DC07D7EE4840F6", + "v1_mic_short_salt_aes_key": "AF688DBBE5AE004BAD0D5E49B6F7D234", + "v1_mic_short_salt_identity_token_hmac_key": "F09E67D34142371B649BC5A06BF027125CAC81971B962F469FB2BAAF1F077B1C", + "v1_mic_short_salt_mic_hmac_key": "DCE2001156BB5C30969FA012D8FE16DB5C599574CC46B61FBA232AE2B184C1F9", + "v1_signature_identity_token_hmac_key": "9E7CA4743B0670FB181CDA233640CBADE4A81E38D4EB4F4BE6188B5548EDC765", + "v1_signature_section_aes_key": "2523471EBF1ED605399CD39AF0B624B0" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "6743665EF1F2534A7EB969AF", - "extended_signed_metadata_key_hmac_key": "355F49A98438F06E21D1501BF501ECCE624C206CC9F9430B0AFBC30041DA605A", - "extended_signed_section_aes_key": "CDD0694A18EF582345EA7C785F928EBD", - "extended_unsigned_metadata_key_hmac_key": "C82654B0FE5E9E50821806DDDD7F8114A79E9C2DA232C557A4B0AC98A514CEC3", - "extended_unsigned_section_aes_key": "E45A101D48BEBF02D446F97609EAFEC2", - "extended_unsigned_section_mic_hmac_key": "CE08A1DD793049E727DA51A8E6BA3B0AF1563D9DA40474FB335199037BFA7CAB", - "key_seed": "E396273E0432224E384CF4CA199547E73E985A3E7886102E0B9ABE911ADBDECC", - "legacy_ldt_key": "78E0EF38C80C61C0B907FF322D047C00664B19B5C704E3698E30B4860EED1814AA25097D7437E972007C5B923DB8D3708B312420EB1708817353D5D3345D40B6", - "legacy_metadata_key_hmac_key": "7266C9A1D0B38E92E975FE7E9E16436F7C596C62A99DCEDC01B26D65651917B9", - "legacy_metadata_nonce": "9CB20BBE3E11C360C90F4433" + "v0_adv_salt_hkdf": { + "adv_salt": "16D1", + "expanded_salt": "24288A2ADBC8574BB7225B2CADBA1F3D" + }, + "v0_identity_token_hkdf": { + "expanded_key": "B21803E7F32A51D47B439095F1229E51", + "v0_identity_token": "6D2145A353E43D90B1487ECD9D20" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "F44E", - "expanded_salt": "CC8D7F5AAE254573F1775BD42817E483" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "C1E9", + "short_salt_nonce": "483CBFACEC1D1468DBCD4FDA" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "A5CEB053C9960AF550E753C41D78D146", - "legacy_metadata_key": "E9E844761B0DA4549C8136A68534" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "03E5070187884CD433FBD176EA5E4A63", + "derived_salt_nonce": "D116BF3B37136C23AB77038C81C6FD87", + "derived_salt_third_de": "2ADBC8DF751DBB23172BBC87F1E6E77E", + "section_extended_salt": "87CA5497D5CE54D75C0B0DBD6CF07B39" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "73E81E7AD1FD560A8492C57B58F0EF4B", - "derived_salt_first_section_no_de": "52C7E3EED057E22BEE798D1EF0AA09F8", - "derived_salt_first_section_third_de": "075B795823F03E6D0877E58125F3BA2B", - "section_salt": "600FE29E6B140E51AFEFA00BB3C72EAF" + "key_seed_hkdf": { + "key_seed": "1AC9F5AC2ED4C99D2B535AC5304F8D481EC6147B39605BFA2B6E21D18006000B", + "v0_identity_token_hmac_key": "B2AB4B284B6CC602FB0403C154FBD19C18FBAC377AB971A35577010F8B0A3A97", + "v0_ldt_key": "4A4DAA2BB754E3E1ED2F473A3B31BA19A2165F0720AFE06EB6B712EB1A2940B8733E71DFFC3854A831CE0E9B8A74A19DF080B11A1FD42FBE7215D1797DBC2736", + "v0_metadata_nonce": "E5ADB3574A0A35ABE1027CF9", + "v1_metadata_nonce": "8F9855477699C38B115C7A54", + "v1_mic_extended_salt_aes_key": "D3B77010859F05271F05F26D1251E8D0", + "v1_mic_extended_salt_identity_token_hmac_key": "5379903CC277C6CA08E17E7EA2A91185F7FB5F9CB75960271AD3089E9F6F4F97", + "v1_mic_extended_salt_mic_hmac_key": "4FDE5BCD4A8CD9B8B0212BCA23A7A9EA49D7C039EBC90AABFECD864F594C5203", + "v1_mic_short_salt_aes_key": "8D5372501B32F7A568349C722CB0F695", + "v1_mic_short_salt_identity_token_hmac_key": "596A1BE90D3806E242B88A5CCE32BC8A2C4FAE2E17BF48B06AEAAD2C5E122032", + "v1_mic_short_salt_mic_hmac_key": "B00D35A3F49F08FBDAFDABB7ECA0A04297850A433A6D11C9FF8F6819F8C39C2B", + "v1_signature_identity_token_hmac_key": "7509D7C29027BC944390DD51AD6F3804D429C3EFBBFE24AD1AFF25FF40C6A8DE", + "v1_signature_section_aes_key": "EC1FA7F03A5E90DBABFFF5EC2495AB5E" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "34D8405F3BEFA5DA663ABD38", - "extended_signed_metadata_key_hmac_key": "A773F7699265B7BAC958E1EBFBA32B1C7B20B10F09DE32FE9F57ADD3190D6037", - "extended_signed_section_aes_key": "3648115AE3CE58377A3CBEF0B3BB2911", - "extended_unsigned_metadata_key_hmac_key": "64CBB1F7D08A526D5FF00C9C55C3B3F050B64DFEA5D2EEA4B1B5978632552635", - "extended_unsigned_section_aes_key": "380C378C2656B11DDBE2DB9BC188C2CB", - "extended_unsigned_section_mic_hmac_key": "2606D0A2E28E00E248C1A72D6441575A6737ED0E291F510F3C683E333F6E7860", - "key_seed": "FF0CA47221553F08490BF23140D052CEC0055B8B4BF7F1217F20E3325C1A14CD", - "legacy_ldt_key": "6CF901B6EF11F104077A3C8FC9DFCD406FFC0A9DEDA5BD1F373D61DF23C020BE603D604C67E2D6C8050AE464EC3F7DC3D6D90732E2E3935C339C5C4BCCD2EB0F", - "legacy_metadata_key_hmac_key": "42AB1CF389132FF5895D75FC9695AE07CEB1C228FD9590FDB49A07F612F11F56", - "legacy_metadata_nonce": "2F0439B0E875A3BFBC685D90" + "v0_adv_salt_hkdf": { + "adv_salt": "9F21", + "expanded_salt": "349E3311FFFF93BE6AC7D0D53D1E36DE" + }, + "v0_identity_token_hkdf": { + "expanded_key": "212FD419A877090C52821F501D62FF97", + "v0_identity_token": "A9ED25A283E0E58F7B127E2B62D6" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "355E", - "expanded_salt": "E6423E380E5D5970BE91AE9CCFCF0636" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "BD70", + "short_salt_nonce": "02C4AC240A3874E831DF38DB" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "2E0A709E2856F0807AE68B785B51F0D1", - "legacy_metadata_key": "26A21171AC7983950B900C2F2979" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "FB3EA084403FA66ECB1C15F9D0AC8396", + "derived_salt_nonce": "4443A4454CF2F491410423CD5F2AE9D0", + "derived_salt_third_de": "90A8D37E587090B7E6D636C6F8D27114", + "section_extended_salt": "38DA154EAF77D994EBBF3CD6FFDE825C" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "40D2F105E8C926AB9D7F7DA89596F555", - "derived_salt_first_section_no_de": "33440FBB64C6BAB6453F7F9A050FFEB5", - "derived_salt_first_section_third_de": "21899A6B8657F7ACB1048C1F683BAC29", - "section_salt": "7B7751AF729D27E3E4C2384D7DB8BEB7" + "key_seed_hkdf": { + "key_seed": "2D9D38BCDA9C2958227BE553C14CEFCF378D5CDCAB880EBF3C43635E07AAFF5A", + "v0_identity_token_hmac_key": "EBD73117325BEECE3A05DB2A1D6323AF7F499E652C61C9008A87A4E47F50EFCE", + "v0_ldt_key": "E28854F65892C5A1D6B92902F6142BA14CD3A74AB95356AA70DA22B3A9193E092B2FA17EBA2B76A08307491C7244789B00075B721AF6C8494D9DA1B3C9CA8F8B", + "v0_metadata_nonce": "9C3813ADD5746412C3214F51", + "v1_metadata_nonce": "6FBC21A602E1E1FB10B5F4EB", + "v1_mic_extended_salt_aes_key": "6EB09E856A0915BA60B3869F321981B4", + "v1_mic_extended_salt_identity_token_hmac_key": "35A04FCBA5B752C97D20158C3C55761C1E6723629BD40C2CD5F28007B14936C5", + "v1_mic_extended_salt_mic_hmac_key": "5F5436261C25D3E5FA446D513B409D5A0C4C27297CBE9F4EE741749154019E21", + "v1_mic_short_salt_aes_key": "B03494A82C3848A67453FB367532112C", + "v1_mic_short_salt_identity_token_hmac_key": "59D6749A1D6AFA4DB973AEAF088FCC0E7BE7D859A2814D641799BB1590496924", + "v1_mic_short_salt_mic_hmac_key": "D3B73C61E28AB288C60D7240B501A074C29A5E328D9BBD8716566B83AB1217A3", + "v1_signature_identity_token_hmac_key": "F85D6CA0DA816F073831FDDF3A0E0FCA9C888FB820762CCD6477DAFB90547E8F", + "v1_signature_section_aes_key": "807F93D9C345DC3AB3D98D43D6FBEAB9" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "765B", + "expanded_salt": "5866D7FC7A27D3A92AB155D7F28348EA" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "0155A616ECEC864B00282442", - "extended_signed_metadata_key_hmac_key": "A824088645C02D59479DC7A74318CC5E07654B61F06478C67CF046E7B85BB252", - "extended_signed_section_aes_key": "D8D511E9F1CBC39FEA821CEC36BF13CF", - "extended_unsigned_metadata_key_hmac_key": "7AA177254B5A06EA9EBAF174490B4117DB213D894B3CFF4F877E4CD83BFAF8C4", - "extended_unsigned_section_aes_key": "E902E759E6DEC479968A81B77B94257A", - "extended_unsigned_section_mic_hmac_key": "CB6FEBD1421C381E3110CF4D3AB26B66DD581D0E0D56675314B389BF26D80231", - "key_seed": "476578AA15A168B1AA7A31A35118008730FB1557A71CB1FB4B49A71103F8900F", - "legacy_ldt_key": "EE0CC526127D2D552A052880C0903B85898507C0247F4635F50B0E4A7F00DF2B96CF572DFF31ADB922932C4A119DE3EC06FCCA823709A090BCD3E4F6E3C89B8D", - "legacy_metadata_key_hmac_key": "65FA3562C23D80DAA78FF2CAC8C6D283D75C674079FAA21E9381E66DDB977AB4", - "legacy_metadata_nonce": "9CC3630D7C3686BE3ACFB38E" + "v0_identity_token_hkdf": { + "expanded_key": "20C0754D69BC2EA57AE634C03D92D592", + "v0_identity_token": "1A1CAE87957F48BB52D07E0172B6" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "9909", - "expanded_salt": "AB6B101F206D124E8B55520349C8F4DC" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "607E", + "short_salt_nonce": "8B511172378BCB1BF0CB674C" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "DF7EC5214955F4A2666598DBCBC1337B", - "legacy_metadata_key": "B37A8ED8D672D20361D8F3D51AAB" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "1E962EC586FE218A8F3A736BA5677B7E", + "derived_salt_nonce": "7399E4535A366989EF412F3EA0F8CE45", + "derived_salt_third_de": "46F2B7D99127C01B68C8B7C8A45CD479", + "section_extended_salt": "6BC0DFA6EBFA267952CB7305F05AD8F2" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "CAF806EE61C9F98C033B6CE648B0A9AA", - "derived_salt_first_section_no_de": "7656E7E7B214432B15B30F17901A592C", - "derived_salt_first_section_third_de": "DAAF85C2FF8DCA2EEAB6524A94EB001A", - "section_salt": "DB0B46A3A5A38945744BC413851D8452" + "key_seed_hkdf": { + "key_seed": "34F2CDC71D38A430F36FA88F159AC2B053B1F339189D0570B68B238E86173239", + "v0_identity_token_hmac_key": "A7724517771962916DFCAAB84400F05865EA15F998EAC81740AE037A413C5425", + "v0_ldt_key": "6F267EC51E8018E9D3CEBF01617BA6E893F01E474BD9710272CA31FF1F61237270BCA8F39E6EEB155E95F2BFE393840EEB26079AB1E03C83FCE12CE52719BAB9", + "v0_metadata_nonce": "CE68A8C49765C41C38B3F0A5", + "v1_metadata_nonce": "27710531902EA355D240D622", + "v1_mic_extended_salt_aes_key": "79E4DBA1E056E59BDCB9BD65A7A805B6", + "v1_mic_extended_salt_identity_token_hmac_key": "8968D34F626250221E226A66FB2E76A4216E3F825745B3605B3F053863EDBFE1", + "v1_mic_extended_salt_mic_hmac_key": "CDD5D25349B3AB7D4885AD124A050704116A5911CE5F379BE998CC7E92DE01AB", + "v1_mic_short_salt_aes_key": "405DCC958551CDD1EC90C4A91D1B87AE", + "v1_mic_short_salt_identity_token_hmac_key": "D06923425C4A028710861654BBFACA9F2FB6B3488B70E9C3C1898152A8DAFA6E", + "v1_mic_short_salt_mic_hmac_key": "421A413608C4344BF7A0E250324337C9ED374636D38D2B35969B6EF434D0D30F", + "v1_signature_identity_token_hmac_key": "D4FADAACB47CC260DEEDB1BBD56131D4FAB54270ACBBFAE975D77079A8554E53", + "v1_signature_section_aes_key": "1F5F9803F64C4A6DCF4BFB0C4FDC800A" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "CDFF", + "expanded_salt": "9F61F76DC1CE3B702DC66772A87A2774" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "0598BCB940F7E46AEB02391A", - "extended_signed_metadata_key_hmac_key": "4B37B033B3911F061486FDD312F423269F345C5EC9D6EE4C9E427B2E2D584159", - "extended_signed_section_aes_key": "E28193D56E706173061F6890E557F96A", - "extended_unsigned_metadata_key_hmac_key": "4817CC85BC549519BEDA10D2257EDADE178B2AA9A710C462DD1190727B9E2E14", - "extended_unsigned_section_aes_key": "197FE5273519A250224BC5E582F599AE", - "extended_unsigned_section_mic_hmac_key": "E2B6BD73DD9018FC0D73C63574CDB10E27D5B84386958EB961B30AED26BD5303", - "key_seed": "2E84B9175D2AF64DCF5592A6CE6A600430F36D1E326268C8628A0790CB832637", - "legacy_ldt_key": "78BF29E2890F20C2359FFD32E20DD90972C660DEE7626DFB2FD89DA4DF2AD34B146973BF7FBC08E477F18199F3861A089BC32F247BDE835A7E34D4242241830C", - "legacy_metadata_key_hmac_key": "6F73D2A56EC7A166FF4965BD10FF5BD53225F9E598E9835120D4D3ECE29839B1", - "legacy_metadata_nonce": "6643257603952C875B40D527" + "v0_identity_token_hkdf": { + "expanded_key": "B6A7CF0DA707E09E2A9FD05FB28802D6", + "v0_identity_token": "028D2AD4E48B79A63C3D6038F453" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "0518", - "expanded_salt": "F5CB5C30716D50337E3597A008774306" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "9D69", + "short_salt_nonce": "1B68E2C018314F5C61591D06" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "C7437CB6E1910745E1D5F85217DE6C3B", - "legacy_metadata_key": "836B4F0F57011DEE3EF79471A08A" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "443DBEF6EA8FBB7E1AED17C651902D8F", + "derived_salt_nonce": "C832DD69A51C4466CC7E4C8FF2C8D830", + "derived_salt_third_de": "996A7355DADC94B04ED4DD5BFF713D10", + "section_extended_salt": "86042432C5C8BFA2ADFEF07E52F76CE1" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "509E424CBCC5964DC827CD736417FDA6", - "derived_salt_first_section_no_de": "8269B8D8C65B9F7519F17EA1B501DCF2", - "derived_salt_first_section_third_de": "313C4472E5BF2EC6F08F8E407433E2D5", - "section_salt": "0C98C48D64771BD607BEE3CFA873E048" - }, "key_seed_hkdf": { - "extended_metadata_nonce": "44F203FA2E7FC2E7DE0985A6", - "extended_signed_metadata_key_hmac_key": "077688F727BAADA52A42D5F4C5DE0FB10028190F68A2950BD1B622A8810A4F84", - "extended_signed_section_aes_key": "74959A95D5FE867B35646442EE2367F0", - "extended_unsigned_metadata_key_hmac_key": "6F5E34C56135FDACC90EDD77AB27D40C583689FDA915AD2B3E053FB287A9B7C9", - "extended_unsigned_section_aes_key": "BFBA8DDD3768E1475F6C2C8167DE2ED7", - "extended_unsigned_section_mic_hmac_key": "7723F9AA8F4694412A19AAF981149B03F332C2CA84EE7A7EA30F0A6CFFE8DF5F", - "key_seed": "C2F7D2B6C8A814B76198CC2838B787E70BE404B7F30C2D3300F00657FF15D4D7", - "legacy_ldt_key": "A675CA45BBA982D8027F96AB8E65B2B267F317805A8E92547DE9B59FF68D1D5D0464197908115D84F1699DF1321671D201AD42918AEDB938A32D4C9145505949", - "legacy_metadata_key_hmac_key": "C8B1A0EA176953817E25A5C2DD984AAA997A0841FD5795EBD596F8954490995D", - "legacy_metadata_nonce": "811CF06428436C54CFFBF02F" + "key_seed": "41CAB11A50B05B768F94CB737A55F0431C37058077CAC227BA33DEAFB13AC126", + "v0_identity_token_hmac_key": "225746B890970F0BA658FD31807704E4792B04142B643292E73897700DF3F7B2", + "v0_ldt_key": "83A452F3DB32B0C30BBCE0188F8674597B16F074155312C4AA50D3543E4F5CBD5F38A3742D0626B532DA9BAABA6976CEFF3F95BD8DC6D30AA945DF8A2ABAEF9B", + "v0_metadata_nonce": "FD6F822707B0AA6F1DA28329", + "v1_metadata_nonce": "EBC62567E6EDFBDA6FB864E1", + "v1_mic_extended_salt_aes_key": "4605C732B31CA709A146D42D49F56964", + "v1_mic_extended_salt_identity_token_hmac_key": "D67C18D39A016F3578F5B36CEDF74FF42AB2D33063004D81223709D34B35B1B3", + "v1_mic_extended_salt_mic_hmac_key": "2F7EFAC31BC19C6414DBFE1E151CA5A9BB2D7FF23816E50DB8D3DBCEF0F651D6", + "v1_mic_short_salt_aes_key": "72EED4197BDD9429F3B227EEEF8D9003", + "v1_mic_short_salt_identity_token_hmac_key": "060C6B4E277154EF8E2AACD29FA7FD561D89EE1B55FE75804AC900B2A14FC6AC", + "v1_mic_short_salt_mic_hmac_key": "9E5E30433992ECC1D0E897740DE7380195AD9D393B172626A04EB4EC1540441D", + "v1_signature_identity_token_hmac_key": "6F8D65A2FDF4A76C612A1CE055862D4E1F3BC758FA9DEA8171281F387C89E89F", + "v1_signature_section_aes_key": "9E1A2442E091482C1AD358CB46EBB449" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "FB05", - "expanded_salt": "5E11580A3CE991235E9CC3C7F2ADF285" + "v0_adv_salt_hkdf": { + "adv_salt": "6BC4", + "expanded_salt": "BCDD2CBC57578E5CE0B7D53841FFC877" + }, + "v0_identity_token_hkdf": { + "expanded_key": "0D231BE24C14382ED04D1AD9E6C9C876", + "v0_identity_token": "A8027285D444310F6180141C6DAF" + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "1304", + "short_salt_nonce": "B1B266BC940E1CB4C0DDB7C6" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "3226C766C11C315F46A2173286D56880", - "legacy_metadata_key": "A3B88B75A089E3D23A9DEE562FCC" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "EC10AA256E69F3BFC61E03E02DAC5572", + "derived_salt_nonce": "C5CD7C8AF453AA0A2E0CFB92B4DEC297", + "derived_salt_third_de": "E72061FB97353A6B46800EAEA02E86A2", + "section_extended_salt": "DC5E1856188626F6FCAF7DEBCD91F83B" } }, { - "extended_section_salt_hkdf": { - "derived_salt_first_section_first_de": "BD4BA99CDFEEFD741D662D819B4D14F8", - "derived_salt_first_section_no_de": "64FB9A93030B0365D875001B3E96C350", - "derived_salt_first_section_third_de": "6A3C091F49BF86800AE97AE1E7E45328", - "section_salt": "E48DDB9A0AB7F195FC4CE1EECE95C905" + "key_seed_hkdf": { + "key_seed": "F9929BC72706329A1D56A0DDE98F41F0C23A4F3316703FC756E1035BD146961E", + "v0_identity_token_hmac_key": "C312A8A15CBF165D135B8934881F7F717ECD9F3EDE6592A73550F7EA63C14083", + "v0_ldt_key": "4BF1CFF058BEED01FA792506A058C94F0FCAEEC2559D16E7E0EB7C458EFD3E11D6BF3E549227B264AFEF830BD7924C54249B25BCC59B4CDD207122936033FDA0", + "v0_metadata_nonce": "B75EDD27FB344C7096F27C89", + "v1_metadata_nonce": "90EDA9020339C51BA2763873", + "v1_mic_extended_salt_aes_key": "1FA685333412CFBE2D673D839419BDA8", + "v1_mic_extended_salt_identity_token_hmac_key": "ED7A20A29073B5B95209AD0CCEC01A27BDD3A5A12DA9489518AB24E2307D2632", + "v1_mic_extended_salt_mic_hmac_key": "2F8F91E46219709D1389613489A418FA8D806A1FB9D9519D0C5D677D55883E5F", + "v1_mic_short_salt_aes_key": "B8A40538DB14E9CCE0157DF49441CDAC", + "v1_mic_short_salt_identity_token_hmac_key": "08569465F0C66A011A7D4FFF67B0FC97690ECE6868E62DF94767E7E9436467D1", + "v1_mic_short_salt_mic_hmac_key": "19D0469CCCA27EE200930615C3D35C27ABE9AAB808752DA5D205E4003A617543", + "v1_signature_identity_token_hmac_key": "FCBBD61A230D9BE84D5E57E4DE4C641F3F9733867290614BE54F33E381EAF517", + "v1_signature_section_aes_key": "39C03BE4FCCB838D975F0B10F2F27FA6" + }, + "v0_adv_salt_hkdf": { + "adv_salt": "DF27", + "expanded_salt": "BB3B8A09918621D2F9AE81B329D4F096" }, - "key_seed_hkdf": { - "extended_metadata_nonce": "E3B03E7EC1C59A97088C54F1", - "extended_signed_metadata_key_hmac_key": "827D30C971E64E75A26047C6288B4709D814C9BE9CC7F46572BB9B343D49A1FC", - "extended_signed_section_aes_key": "31F40B5580260656F90D47F58C6FFE3E", - "extended_unsigned_metadata_key_hmac_key": "EEF0C2830B30035F6EC56904F132AEFB4098A88951CC33286939CB9789AD1638", - "extended_unsigned_section_aes_key": "A60216A1AC950D161D157EDD08C98073", - "extended_unsigned_section_mic_hmac_key": "8AADFDEEA0DF6A71D95D3570846F53A4FEC594274282DD4BD227C4BD64FF98AF", - "key_seed": "0BE1EE39610085A3BA277EBBEAD2872369707174526F23FFC67AA8BA962ABB1F", - "legacy_ldt_key": "8D4922931521FB95569442172FAC2118E396C92702DAFC1DC3CB9E205C0E3ED7896179B06D1A0B9528B936E2F85B6FFC741F8654016FD47107333BD247E96EA5", - "legacy_metadata_key_hmac_key": "FAE1B3B936C6756EFD9AEBCA751389891DACDEE3EAFD3A808D0797F0C128F544", - "legacy_metadata_nonce": "094573CD360778668C292C9D" + "v0_identity_token_hkdf": { + "expanded_key": "72DE095B1A0271E0042F668244A1255B", + "v0_identity_token": "ADFE0051B256B9778548300C4F17" }, - "legacy_adv_salt_hkdf": { - "adv_salt": "3E9E", - "expanded_salt": "D7A319F27E248AB5CA95967784D6AF77" + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": "2816", + "short_salt_nonce": "7DB3F25CD050360CEB4DC7D0" }, - "legacy_metadata_key_hkdf": { - "expanded_key": "15896E896566D60C3810FAADC94A05CE", - "legacy_metadata_key": "C08895650105CE9C165A9BCA08D8" + "v1_section_extended_salt_hkdf": { + "derived_salt_first_de": "ADACCCB5226C9A33368DCA3CDB62BBA1", + "derived_salt_nonce": "00AA84F4608746BEC8A17749584F7229", + "derived_salt_third_de": "C925E34CF796B07300BFDA0B91172D86", + "section_extended_salt": "65D6AA69B72031C537A1EBD7D1F16B7F" } } -] \ No newline at end of file +]
diff --git a/nearby/presence/np_hkdf/src/lib.rs b/nearby/presence/np_hkdf/src/lib.rs index 8201f38..bf82169 100644 --- a/nearby/presence/np_hkdf/src/lib.rs +++ b/nearby/presence/np_hkdf/src/lib.rs
@@ -22,30 +22,29 @@ #[cfg(feature = "std")] extern crate std; -use core::marker; -use crypto_provider::{aes::Aes128Key, hkdf::Hkdf, hmac::Hmac, CryptoProvider}; +use crypto_provider::aead::Aead; +use crypto_provider::{aes, aes::Aes128Key, hkdf::Hkdf, hmac::Hmac, CryptoProvider}; pub mod v1_salt; /// A wrapper around the common NP usage of HMAC-SHA256. /// /// These are generally derived via HKDF, but could be used for any HMAC-SHA256 key. -#[derive(Debug)] -pub struct NpHmacSha256Key<C: CryptoProvider> { +#[derive(Clone, Debug)] +pub struct NpHmacSha256Key { /// Nearby Presence uses 32-byte HMAC keys. /// /// Inside the HMAC algorithm they will be padded to 64 bytes. key: [u8; 32], - c_phantom: marker::PhantomData<C>, } -impl<C: CryptoProvider> NpHmacSha256Key<C> { +impl NpHmacSha256Key { /// Build a fresh HMAC instance. /// /// Since each HMAC is modified as data is fed to it, HMACs should not be reused. /// /// See also [Self::calculate_hmac] for simple use cases. - pub fn build_hmac(&self) -> C::HmacSha256 { + pub fn build_hmac<C: CryptoProvider>(&self) -> C::HmacSha256 { C::HmacSha256::new_from_key(self.key) } @@ -57,8 +56,8 @@ /// Build an HMAC, update it with the provided `data`, and finalize it, returning the resulting /// MAC. This is convenient for one-and-done HMAC usage rather than incrementally accumulating /// the final MAC. - pub fn calculate_hmac(&self, data: &[u8]) -> [u8; 32] { - let mut hmac = self.build_hmac(); + pub fn calculate_hmac<C: CryptoProvider>(&self, data: &[u8]) -> [u8; 32] { + let mut hmac = self.build_hmac::<C>(); hmac.update(data); hmac.finalize() } @@ -67,26 +66,20 @@ /// /// This is convenient for one-and-done HMAC usage rather than incrementally accumulating /// the final MAC. - pub fn verify_hmac( + pub fn verify_hmac<C: CryptoProvider>( &self, data: &[u8], expected_mac: [u8; 32], ) -> Result<(), crypto_provider::hmac::MacError> { - let mut hmac = self.build_hmac(); + let mut hmac = self.build_hmac::<C>(); hmac.update(data); hmac.verify(expected_mac) } } -impl<C: CryptoProvider> From<[u8; 32]> for NpHmacSha256Key<C> { +impl From<[u8; 32]> for NpHmacSha256Key { fn from(key: [u8; 32]) -> Self { - Self { key, c_phantom: Default::default() } - } -} - -impl<C: CryptoProvider> Clone for NpHmacSha256Key<C> { - fn clone(&self) -> Self { - Self { key: self.key, c_phantom: Default::default() } + Self { key } } } @@ -106,84 +99,142 @@ /// LDT key used to decrypt a legacy advertisement #[allow(clippy::expect_used)] - pub fn legacy_ldt_key(&self) -> ldt::LdtKey<xts_aes::XtsAes128Key> { + pub fn v0_ldt_key(&self) -> ldt::LdtKey<xts_aes::XtsAes128Key> { ldt::LdtKey::from_concatenated( - &self.hkdf.derive_array(b"Legacy LDT key").expect("LDT key is a valid length"), + &self.hkdf.derive_array(b"V0 LDT key").expect("LDT key is a valid length"), ) } - /// HMAC key used when verifying the raw metadata key extracted from an advertisement - pub fn legacy_metadata_key_hmac_key(&self) -> NpHmacSha256Key<C> { - self.hkdf.derive_hmac_sha256_key(b"Legacy metadata key verification HMAC key") + /// HMAC key used when verifying the raw identity token extracted from an advertisement + pub fn v0_identity_token_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"V0 Identity token verification HMAC key") } /// AES-GCM nonce used when decrypting metadata #[allow(clippy::expect_used)] - pub fn legacy_metadata_nonce(&self) -> [u8; 12] { - self.hkdf.derive_array(b"Legacy Metadata Nonce").expect("Nonce is a valid length") + pub fn v0_metadata_nonce(&self) -> <C::Aes128Gcm as Aead>::Nonce { + self.hkdf.derive_array(b"V0 Metadata nonce").expect("Nonce is a valid length") } /// AES-GCM nonce used when decrypting metadata. /// /// Shared between signed and unsigned since they use the same credential. #[allow(clippy::expect_used)] - pub fn extended_metadata_nonce(&self) -> [u8; 12] { - self.hkdf.derive_array(b"Metadata Nonce").expect("Nonce is a valid length") + pub fn v1_metadata_nonce(&self) -> <C::Aes128Gcm as Aead>::Nonce { + self.hkdf.derive_array(b"V1 Metadata nonce").expect("Nonce is a valid length") } - /// HMAC key used when verifying the raw metadata key extracted from an advertisement - pub fn extended_unsigned_metadata_key_hmac_key(&self) -> NpHmacSha256Key<C> { - self.hkdf.derive_hmac_sha256_key(b"Unsigned Section metadata key HMAC key") + /// Derived keys for MIC short salt sections + pub fn v1_mic_short_salt_keys(&self) -> MicShortSaltSectionKeys<'_, C> { + MicShortSaltSectionKeys { hkdf: &self.hkdf } } - /// HMAC key used when verifying the raw metadata key extracted from an extended signed advertisement - #[allow(clippy::expect_used)] - pub fn extended_signed_metadata_key_hmac_key(&self) -> NpHmacSha256Key<C> { - self.hkdf.derive_hmac_sha256_key(b"Signed Section metadata key HMAC key") + /// Derived keys for MIC extended salt sections + pub fn v1_mic_extended_salt_keys(&self) -> MicExtendedSaltSectionKeys<'_, C> { + MicExtendedSaltSectionKeys { hkdf: &self.hkdf } } - /// AES128 key used when decrypting an extended signed section - #[allow(clippy::expect_used)] - pub fn extended_signed_section_aes_key(&self) -> Aes128Key { - self.hkdf.derive_aes128_key(b"Signed Section AES key") + /// Derived keys for MIC signature sections + pub fn v1_signature_keys(&self) -> SignatureSectionKeys<'_, C> { + SignatureSectionKeys { hkdf: &self.hkdf } } } -impl<C: CryptoProvider> UnsignedSectionKeys<C> for NpKeySeedHkdf<C> { +/// Derived keys for MIC short salt sections +pub struct MicShortSaltSectionKeys<'a, C: CryptoProvider> { + hkdf: &'a NpHkdf<C>, +} + +impl<'a, C: CryptoProvider> MicShortSaltSectionKeys<'a, C> { + /// HMAC-SHA256 key used when verifying a section's ciphertext + pub fn mic_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"MIC Section short salt HMAC key") + } +} + +impl<'a, C: CryptoProvider> DerivedSectionKeys<C> for MicShortSaltSectionKeys<'a, C> { fn aes_key(&self) -> Aes128Key { - self.hkdf.derive_aes128_key(b"Unsigned Section AES key") + self.hkdf.derive_aes128_key(b"MIC Section short salt AES key") } - fn hmac_key(&self) -> NpHmacSha256Key<C> { - self.hkdf.derive_hmac_sha256_key(b"Unsigned Section HMAC key") + fn identity_token_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"MIC Section short salt identity token HMAC key") } } -/// Derived keys for V1 MIC (unsigned) sections -pub trait UnsignedSectionKeys<C: CryptoProvider> { - /// AES128 key used when decrypting an extended unsigned section +/// Derived keys for MIC extended salt sections +pub struct MicExtendedSaltSectionKeys<'a, C: CryptoProvider> { + hkdf: &'a NpHkdf<C>, +} + +impl<'a, C: CryptoProvider> MicExtendedSaltSectionKeys<'a, C> { + /// HMAC-SHA256 key used when verifying a section's ciphertext + pub fn mic_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"MIC Section extended salt HMAC key") + } +} + +impl<'a, C: CryptoProvider> DerivedSectionKeys<C> for MicExtendedSaltSectionKeys<'a, C> { + fn aes_key(&self) -> Aes128Key { + self.hkdf.derive_aes128_key(b"MIC Section extended salt AES key") + } + + fn identity_token_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"MIC Section extended salt identity token HMAC key") + } +} + +/// Derived keys for Signature sections +pub struct SignatureSectionKeys<'a, C: CryptoProvider> { + hkdf: &'a NpHkdf<C>, +} + +impl<'a, C: CryptoProvider> DerivedSectionKeys<C> for SignatureSectionKeys<'a, C> { + fn aes_key(&self) -> Aes128Key { + self.hkdf.derive_aes128_key(b"Signature Section AES key") + } + + fn identity_token_hmac_key(&self) -> NpHmacSha256Key { + self.hkdf.derive_hmac_sha256_key(b"Signature Section identity token HMAC key") + } +} + +/// Derived keys for encrypted V1 sections +pub trait DerivedSectionKeys<C: CryptoProvider> { + /// AES128 key used when encrypting a section's ciphertext fn aes_key(&self) -> Aes128Key; - /// HMAC-SHA256 key used when verifying an extended unsigned section - fn hmac_key(&self) -> NpHmacSha256Key<C>; + /// HMAC-SHA256 key used when verifying a section's plaintext identity token + fn identity_token_hmac_key(&self) -> NpHmacSha256Key; } /// Expand a legacy salt into the expanded salt used with XOR padding in LDT. #[allow(clippy::expect_used)] -pub fn legacy_ldt_expanded_salt<const B: usize, C: CryptoProvider>(salt: &[u8; 2]) -> [u8; B] { - simple_np_hkdf_expand::<B, C>(salt, b"Legacy LDT salt pad") - // the padded salt is the tweak size of a tweakable block cipher, which shouldn't be - // anywhere close to the max HKDF size (255 * 32) +pub fn v0_ldt_expanded_salt<C: CryptoProvider>(salt: &[u8; 2]) -> [u8; aes::BLOCK_SIZE] { + simple_np_hkdf_expand::<{ aes::BLOCK_SIZE }, C>(salt, b"V0 LDT salt pad") + // XTS tweak size is the block cipher's block size .expect("Tweak size is a valid HKDF size") } -/// Expand a legacy (short) raw metadata key into an AES128 key. +/// Expand a v0 identity token into an AES128 metadata key. #[allow(clippy::expect_used)] -pub fn legacy_metadata_expanded_key<C: CryptoProvider>(raw_metadata_key: &[u8; 14]) -> [u8; 16] { - simple_np_hkdf_expand::<16, C>(raw_metadata_key, b"Legacy metadata key expansion") +pub fn v0_metadata_expanded_key<C: CryptoProvider>(identity_token: &[u8; 14]) -> [u8; 16] { + simple_np_hkdf_expand::<16, C>(identity_token, b"V0 Metadata key expansion") .expect("AES128 key is a valid HKDF size") } +/// Expand an extended MIC section's short salt into an AES-CTR nonce. +#[allow(clippy::expect_used)] +pub fn extended_mic_section_short_salt_nonce<C: CryptoProvider>( + salt: [u8; 2], +) -> aes::ctr::AesCtrNonce { + simple_np_hkdf_expand::<{ aes::ctr::AES_CTR_NONCE_LEN }, C>( + salt.as_slice(), + b"MIC Section short salt nonce", + ) + .expect("AES-CTR nonce is a valid HKDF size") +} + /// Build an HKDF using the NP HKDF salt, calculate output, and discard the HKDF. /// If using the NP key seed as IKM, see [NpKeySeedHkdf] instead. /// @@ -198,12 +249,12 @@ } /// Construct an HKDF with the Nearby Presence salt and provided `ikm` -pub fn np_salt_hkdf<C: CryptoProvider>(ikm: &[u8]) -> C::HkdfSha256 { +fn np_salt_hkdf<C: CryptoProvider>(ikm: &[u8]) -> C::HkdfSha256 { C::HkdfSha256::new(Some(NP_HKDF_SALT), ikm) } /// NP-flavored HKDF operations for common derived output types -pub struct NpHkdf<C: CryptoProvider> { +struct NpHkdf<C: CryptoProvider> { hkdf: C::HkdfSha256, } @@ -222,7 +273,7 @@ /// Derive an HMAC-SHA256 key using the provided `info` #[allow(clippy::expect_used)] - pub fn derive_hmac_sha256_key(&self, info: &[u8]) -> NpHmacSha256Key<C> { + pub fn derive_hmac_sha256_key(&self, info: &[u8]) -> NpHmacSha256Key { self.derive_array(info).expect("HMAC-SHA256 keys are a valid length").into() } /// Derive an AES-128 key using the provided `info`
diff --git a/nearby/presence/np_hkdf/src/v1_salt.rs b/nearby/presence/np_hkdf/src/v1_salt.rs index 94e6855..cfa1f51 100644 --- a/nearby/presence/np_hkdf/src/v1_salt.rs +++ b/nearby/presence/np_hkdf/src/v1_salt.rs
@@ -14,45 +14,44 @@ //! Salt used in a V1 advertisement. use crate::np_salt_hkdf; -use core::fmt; -use crypto_provider::hkdf::Hkdf; -use crypto_provider::CryptoProvider; +use crypto_provider::{hkdf::Hkdf, CryptoProvider, CryptoRng, FromCryptoRng}; + +/// Length of a V1 extended salt +pub const EXTENDED_SALT_LEN: usize = 16; /// Salt optionally included in V1 advertisement header. /// /// The salt is never used directly; rather, a derived salt should be extracted as needed for any /// section or DE that requires it. -#[derive(Clone)] -pub struct V1Salt<C> -where - C: CryptoProvider, -{ - // kept around for Eq and Debug impl, should not be exposed - data: [u8; 16], - hkdf: C::HkdfSha256, +#[derive(Clone, Copy, PartialEq, Debug, Eq)] +pub struct ExtendedV1Salt { + data: [u8; EXTENDED_SALT_LEN], } -impl<C: CryptoProvider> V1Salt<C> { - /// Derive a salt for a particular section and DE, if applicable. +impl ExtendedV1Salt { + /// Derive a salt for a particular DE, if applicable. /// /// Returns none if the requested size is larger than HKDF allows or if offset arithmetic /// overflows. - pub fn derive<const N: usize>(&self, de: Option<DataElementOffset>) -> Option<[u8; N]> { + pub fn derive<const N: usize, C: CryptoProvider>( + &self, + de: Option<DataElementOffset>, + ) -> Option<[u8; N]> { + let hkdf = np_salt_hkdf::<C>(&self.data); let mut arr = [0_u8; N]; // 0-based offsets -> 1-based indices w/ 0 indicating not present - self.hkdf - .expand_multi_info( - &[ - b"V1 derived salt", - &de.and_then(|d| d.offset.checked_add(1)) - .map(|o| o.into()) - .unwrap_or(0_u32) - .to_be_bytes(), - ], - &mut arr, - ) - .map(|_| arr) - .ok() + hkdf.expand_multi_info( + &[ + b"V1 derived salt", + &de.and_then(|d| d.offset.checked_add(1)) + .map(|o| o.into()) + .unwrap_or(0_u32) + .to_be_bytes(), + ], + &mut arr, + ) + .map(|_| arr) + .ok() } /// Returns the salt bytes as a slice @@ -61,38 +60,29 @@ } /// Returns the salt bytes as an array - pub fn into_array(self) -> [u8; 16] { + pub fn into_array(self) -> [u8; EXTENDED_SALT_LEN] { self.data } /// Returns the salt bytes as a reference to an array - pub fn as_array_ref(&self) -> &[u8; 16] { + pub fn bytes(&self) -> &[u8; EXTENDED_SALT_LEN] { &self.data } } -impl<C: CryptoProvider> From<[u8; 16]> for V1Salt<C> { - fn from(arr: [u8; 16]) -> Self { - Self { data: arr, hkdf: np_salt_hkdf::<C>(&arr) } +impl From<[u8; EXTENDED_SALT_LEN]> for ExtendedV1Salt { + fn from(arr: [u8; EXTENDED_SALT_LEN]) -> Self { + Self { data: arr } } } -impl<C: CryptoProvider> PartialEq<Self> for V1Salt<C> { - fn eq(&self, other: &Self) -> bool { - // no need to compare hkdf (which it doesn't allow anyway) - self.data == other.data +impl FromCryptoRng for ExtendedV1Salt { + fn new_random<R: CryptoRng>(rng: &mut R) -> Self { + rng.gen::<[u8; EXTENDED_SALT_LEN]>().into() } } -impl<C: CryptoProvider> Eq for V1Salt<C> {} - -impl<C: CryptoProvider> fmt::Debug for V1Salt<C> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.data.fmt(f) - } -} - -/// Offset of a data element in its containing section, used with [V1Salt]. +/// Offset of a data element in its containing section, used with [ExtendedV1Salt]. #[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)] pub struct DataElementOffset { /// 0-based offset of the DE in the advertisement
diff --git a/nearby/presence/np_hkdf/tests/hmac.rs b/nearby/presence/np_hkdf/tests/hmac.rs index 4ebef5a..9cb0357 100644 --- a/nearby/presence/np_hkdf/tests/hmac.rs +++ b/nearby/presence/np_hkdf/tests/hmac.rs
@@ -21,11 +21,11 @@ let data = &[1_u8; 32]; let hmac_key = [2; 32]; - let hmac = NpHmacSha256Key::<CryptoProviderImpl>::from(hmac_key); + let hmac = NpHmacSha256Key::from(hmac_key); - let mac = hmac.calculate_hmac(data); + let mac = hmac.calculate_hmac::<CryptoProviderImpl>(data); - assert_eq!(Ok(()), hmac.verify_hmac(data, mac)); + assert_eq!(Ok(()), hmac.verify_hmac::<CryptoProviderImpl>(data, mac)); } #[test] @@ -33,10 +33,10 @@ let data = &[1_u8; 32]; let hmac_key = [2; 32]; - let hmac = NpHmacSha256Key::<CryptoProviderImpl>::from(hmac_key); + let hmac = NpHmacSha256Key::from(hmac_key); - let _mac = hmac.calculate_hmac(data); + let _mac = hmac.calculate_hmac::<CryptoProviderImpl>(data); // wrong mac - assert_eq!(Err(MacError), hmac.verify_hmac(data, [0xFF; 32])); + assert_eq!(Err(MacError), hmac.verify_hmac::<CryptoProviderImpl>(data, [0xFF; 32])); }
diff --git a/nearby/presence/np_hkdf/tests/test_vectors.rs b/nearby/presence/np_hkdf/tests/test_vectors.rs index 175e73e..a00e747 100644 --- a/nearby/presence/np_hkdf/tests/test_vectors.rs +++ b/nearby/presence/np_hkdf/tests/test_vectors.rs
@@ -17,12 +17,11 @@ use anyhow::anyhow; use crypto_provider::aes::AesKey; use crypto_provider_default::CryptoProviderImpl; -use np_hkdf::{v1_salt::V1Salt, *}; -use rand::Rng as _; -use rand_ext::seeded_rng; +use np_hkdf::{v1_salt::ExtendedV1Salt, *}; use serde_json::json; use std::{fs, io::Read as _}; use test_helper::extract_key_array; +use test_vector_hkdf::TestVectorHkdf; #[test] fn hkdf_test_vectors() -> Result<(), anyhow::Error> { @@ -42,76 +41,97 @@ let key_seed = extract_key_array::<32>(group, "key_seed"); let hkdf = NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); assert_eq!( - extract_key_array::<64>(group, "legacy_ldt_key"), - hkdf.legacy_ldt_key().as_concatenated() + extract_key_array::<64>(group, "v0_ldt_key"), + hkdf.v0_ldt_key().as_concatenated() ); assert_eq!( - &extract_key_array::<32>(group, "legacy_metadata_key_hmac_key"), - hkdf.legacy_metadata_key_hmac_key().as_bytes() + &extract_key_array::<32>(group, "v0_identity_token_hmac_key"), + hkdf.v0_identity_token_hmac_key().as_bytes() ); assert_eq!( - extract_key_array::<12>(group, "legacy_metadata_nonce"), - hkdf.legacy_metadata_nonce() + extract_key_array::<12>(group, "v0_metadata_nonce"), + hkdf.v0_metadata_nonce() ); assert_eq!( - extract_key_array::<12>(group, "extended_metadata_nonce"), - hkdf.extended_metadata_nonce() + extract_key_array::<12>(group, "v1_metadata_nonce"), + hkdf.v1_metadata_nonce() ); assert_eq!( - &extract_key_array::<32>(group, "extended_unsigned_metadata_key_hmac_key"), - hkdf.extended_unsigned_metadata_key_hmac_key().as_bytes() + &extract_key_array::<32>(group, "v1_mic_short_salt_identity_token_hmac_key"), + hkdf.v1_mic_short_salt_keys().identity_token_hmac_key().as_bytes() ); assert_eq!( - extract_key_array::<16>(group, "extended_unsigned_section_aes_key"), - *UnsignedSectionKeys::aes_key(&hkdf).as_array() + extract_key_array::<16>(group, "v1_mic_short_salt_aes_key"), + *hkdf.v1_mic_short_salt_keys().aes_key().as_array() ); assert_eq!( - &extract_key_array::<32>(group, "extended_unsigned_section_mic_hmac_key"), - UnsignedSectionKeys::hmac_key(&hkdf).as_bytes() + &extract_key_array::<32>(group, "v1_mic_short_salt_mic_hmac_key"), + hkdf.v1_mic_short_salt_keys().mic_hmac_key().as_bytes() ); assert_eq!( - &extract_key_array::<32>(group, "extended_signed_metadata_key_hmac_key"), - hkdf.extended_signed_metadata_key_hmac_key().as_bytes() + &extract_key_array::<32>(group, "v1_mic_extended_salt_identity_token_hmac_key"), + hkdf.v1_mic_extended_salt_keys().identity_token_hmac_key().as_bytes() ); assert_eq!( - extract_key_array::<16>(group, "extended_signed_section_aes_key"), - *hkdf.extended_signed_section_aes_key().as_array() + extract_key_array::<16>(group, "v1_mic_extended_salt_aes_key"), + *hkdf.v1_mic_extended_salt_keys().aes_key().as_array() + ); + assert_eq!( + &extract_key_array::<32>(group, "v1_mic_extended_salt_mic_hmac_key"), + hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes() + ); + assert_eq!( + &extract_key_array::<32>(group, "v1_signature_identity_token_hmac_key"), + hkdf.v1_signature_keys().identity_token_hmac_key().as_bytes() + ); + assert_eq!( + extract_key_array::<16>(group, "v1_signature_section_aes_key"), + *hkdf.v1_signature_keys().aes_key().as_array() ); } { - let group = &tc["legacy_adv_salt_hkdf"]; + let group = &tc["v0_adv_salt_hkdf"]; let ikm = extract_key_array::<2>(group, "adv_salt"); assert_eq!( extract_key_array::<16>(group, "expanded_salt"), - legacy_ldt_expanded_salt::<16, CryptoProviderImpl>(&ikm) + v0_ldt_expanded_salt::<CryptoProviderImpl>(&ikm) ) } { - let group = &tc["legacy_metadata_key_hkdf"]; - let ikm = extract_key_array::<14>(group, "legacy_metadata_key"); + let group = &tc["v0_identity_token_hkdf"]; + let ikm = extract_key_array::<14>(group, "v0_identity_token"); assert_eq!( extract_key_array::<16>(group, "expanded_key"), - legacy_metadata_expanded_key::<CryptoProviderImpl>(&ikm) + v0_metadata_expanded_key::<CryptoProviderImpl>(&ikm) ) } { - let group = &tc["extended_section_salt_hkdf"]; - let ikm = extract_key_array::<16>(group, "section_salt"); - let salt = V1Salt::<CryptoProviderImpl>::from(ikm); + let group = &tc["v1_section_extended_salt_hkdf"]; + let ikm = extract_key_array::<16>(group, "section_extended_salt"); + let salt = ExtendedV1Salt::from(ikm); assert_eq!( - extract_key_array::<16>(group, "derived_salt_first_section_no_de"), - salt.derive(None).unwrap(), + extract_key_array::<16>(group, "derived_salt_nonce"), + salt.derive::<16, CryptoProviderImpl>(None).unwrap(), ); assert_eq!( - extract_key_array::<16>(group, "derived_salt_first_section_first_de"), - salt.derive(Some(0.into())).unwrap(), + extract_key_array::<16>(group, "derived_salt_first_de"), + salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap(), ); assert_eq!( - extract_key_array::<16>(group, "derived_salt_first_section_third_de"), - salt.derive(Some(2.into())).unwrap(), + extract_key_array::<16>(group, "derived_salt_third_de"), + salt.derive::<16, CryptoProviderImpl>(Some(2.into())).unwrap(), + ); + } + + { + let group = &tc["v1_mic_section_short_salt_hkdf"]; + let ikm = extract_key_array::<2>(group, "section_short_salt"); + assert_eq!( + extract_key_array::<12>(group, "short_salt_nonce"), + extended_mic_section_short_salt_nonce::<CryptoProviderImpl>(ikm), ); } } @@ -121,53 +141,70 @@ // disable unless you want to print out a new set of test vectors #[ignore] +#[allow(clippy::panic)] #[test] fn gen_test_vectors() { - let mut rng = seeded_rng(); - let mut array = Vec::<serde_json::Value>::new(); - for _ in 0..100 { - let key_seed: [u8; 32] = rng.gen(); - let legacy_adv_salt: [u8; 2] = rng.gen(); - let legacy_metadata_key: [u8; 14] = rng.gen(); - let adv_salt_bytes: [u8; 16] = rng.gen(); - let extended_adv_salt = V1Salt::<CryptoProviderImpl>::from(adv_salt_bytes); + for i in 0_u32..100 { + // build "random" things in a repeatable way so future changes don't + // rebuild unrelated things, with some /dev/random thrown in for good measure + let test_vector_seed_hkdf = TestVectorHkdf::<CryptoProviderImpl>::new( + "NP HKDF test vectors pb4qoNqM9aL/ezSC2FU5EQzu8JJoJ25B+rLqbU5kVN8", + &i.to_be_bytes(), + ); + + let key_seed: [u8; 32] = test_vector_seed_hkdf.derive_array("key seed"); + let v0_adv_salt: [u8; 2] = test_vector_seed_hkdf.derive_array("legacy adv salt"); + let v0_identity_token: [u8; 14] = test_vector_seed_hkdf.derive_array("v0 identity token"); + let extended_salt_bytes: [u8; 16] = + test_vector_seed_hkdf.derive_array("v1 section extended salt"); + let v1_mic_short_salt: [u8; 2] = + test_vector_seed_hkdf.derive_array("v1 mic section short salt"); + let v1_extended_salt = ExtendedV1Salt::from(extended_salt_bytes); let key_seed_hkdf = NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed); array .push(json!({ "key_seed_hkdf": { "key_seed": hex::encode_upper(key_seed), - "legacy_ldt_key": hex::encode_upper(key_seed_hkdf.legacy_ldt_key().as_concatenated()), - "legacy_metadata_key_hmac_key": - hex::encode_upper(key_seed_hkdf.legacy_metadata_key_hmac_key().as_bytes()), - "legacy_metadata_nonce": hex::encode_upper(key_seed_hkdf.legacy_metadata_nonce()), - "extended_metadata_nonce": hex::encode_upper(key_seed_hkdf.extended_metadata_nonce()), - "extended_unsigned_metadata_key_hmac_key": hex::encode_upper(key_seed_hkdf.extended_unsigned_metadata_key_hmac_key().as_bytes()), - "extended_unsigned_section_aes_key": hex::encode_upper(UnsignedSectionKeys::<CryptoProviderImpl>::aes_key(&key_seed_hkdf).as_array()), - "extended_unsigned_section_mic_hmac_key": hex::encode_upper(UnsignedSectionKeys::<CryptoProviderImpl>::hmac_key(&key_seed_hkdf).as_bytes()), - "extended_signed_metadata_key_hmac_key": hex::encode_upper(key_seed_hkdf.extended_signed_metadata_key_hmac_key().as_bytes()), - "extended_signed_section_aes_key": hex::encode_upper(key_seed_hkdf.extended_signed_section_aes_key().as_array()), + "v0_ldt_key": hex::encode_upper(key_seed_hkdf.v0_ldt_key().as_concatenated()), + "v0_identity_token_hmac_key": + hex::encode_upper(key_seed_hkdf.v0_identity_token_hmac_key().as_bytes()), + "v0_metadata_nonce": hex::encode_upper(key_seed_hkdf.v0_metadata_nonce()), + "v1_metadata_nonce": hex::encode_upper(key_seed_hkdf.v1_metadata_nonce()), + "v1_mic_short_salt_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().identity_token_hmac_key().as_bytes()), + "v1_mic_short_salt_aes_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().aes_key().as_array()), + "v1_mic_short_salt_mic_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_short_salt_keys().mic_hmac_key().as_bytes()), + "v1_mic_extended_salt_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().identity_token_hmac_key().as_bytes()), + "v1_mic_extended_salt_aes_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().aes_key().as_array()), + "v1_mic_extended_salt_mic_hmac_key": hex::encode_upper(key_seed_hkdf.v1_mic_extended_salt_keys().mic_hmac_key().as_bytes()), + "v1_signature_identity_token_hmac_key": hex::encode_upper(key_seed_hkdf.v1_signature_keys().identity_token_hmac_key().as_bytes()), + "v1_signature_section_aes_key": hex::encode_upper(key_seed_hkdf.v1_signature_keys().aes_key().as_array()), }, - "legacy_adv_salt_hkdf": { - "adv_salt": hex::encode_upper(legacy_adv_salt), - "expanded_salt": hex::encode_upper(legacy_ldt_expanded_salt::<16, CryptoProviderImpl>(&legacy_adv_salt)) + "v0_adv_salt_hkdf": { + "adv_salt": hex::encode_upper(v0_adv_salt), + "expanded_salt": hex::encode_upper(v0_ldt_expanded_salt::<CryptoProviderImpl>(&v0_adv_salt)) }, - "legacy_metadata_key_hkdf": { - "legacy_metadata_key": hex::encode_upper(legacy_metadata_key), + "v0_identity_token_hkdf": { + "v0_identity_token": hex::encode_upper(v0_identity_token), "expanded_key": - hex::encode_upper(legacy_metadata_expanded_key::<CryptoProviderImpl>(&legacy_metadata_key)) + hex::encode_upper(v0_metadata_expanded_key::<CryptoProviderImpl>(&v0_identity_token)) }, - "extended_section_salt_hkdf": { - "section_salt": hex::encode_upper(adv_salt_bytes), + "v1_section_extended_salt_hkdf": { + "section_extended_salt": hex::encode_upper(v1_extended_salt.bytes()), // 0-based offsets -> 1-based indexing - "derived_salt_first_section_no_de": hex::encode_upper(extended_adv_salt.derive::<16>(None).unwrap()), - "derived_salt_first_section_first_de": hex::encode_upper(extended_adv_salt.derive::<16>(Some(0.into())).unwrap()), - "derived_salt_first_section_third_de": hex::encode_upper(extended_adv_salt.derive::<16>(Some(2.into())).unwrap()), + "derived_salt_nonce": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(None).unwrap()), + "derived_salt_first_de": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(Some(0.into())).unwrap()), + "derived_salt_third_de": hex::encode_upper(v1_extended_salt.derive::<16, CryptoProviderImpl>(Some(2.into())).unwrap()), + }, + "v1_mic_section_short_salt_hkdf": { + "section_short_salt": hex::encode_upper(v1_mic_short_salt), + "short_salt_nonce": hex::encode_upper(extended_mic_section_short_salt_nonce::<CryptoProviderImpl>(v1_mic_short_salt)), } })); } println!("{}", serde_json::ser::to_string_pretty(&array).unwrap()); + panic!("Don't leave this test enabled. Meanwhile, enjoy the text output above."); }
diff --git a/nearby/presence/np_java_ffi/.gitignore b/nearby/presence/np_java_ffi/.gitignore new file mode 100644 index 0000000..cafbf51 --- /dev/null +++ b/nearby/presence/np_java_ffi/.gitignore
@@ -0,0 +1,8 @@ +# Ignore Gradle project-specific cache directory +/.gradle + +# Ignore Gradle build output directory +/build + +# Ignore IDEA dir +/.idea
diff --git a/nearby/presence/np_java_ffi/Cargo.toml b/nearby/presence/np_java_ffi/Cargo.toml new file mode 100644 index 0000000..556b481 --- /dev/null +++ b/nearby/presence/np_java_ffi/Cargo.toml
@@ -0,0 +1,22 @@ +[package] +name = "np_java_ffi" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[lints] +workspace = true + +[dependencies] +handle_map.workspace = true +np_adv.workspace = true +np_ffi_core.workspace = true +pourover.workspace = true +pourover_macro.workspace = true +crypto_provider_default.workspace = true # for setting features from cmdline + +jni.workspace = true + +[lib] +# JNI wants a .so or equivalent +crate-type = ["cdylib"]
diff --git a/nearby/presence/np_java_ffi/build.gradle.kts b/nearby/presence/np_java_ffi/build.gradle.kts new file mode 100644 index 0000000..69d73c4 --- /dev/null +++ b/nearby/presence/np_java_ffi/build.gradle.kts
@@ -0,0 +1,54 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + `java-library` +} + +repositories { + mavenCentral() + google() +} + +dependencies { + implementation("androidx.annotation:annotation:1.6.0") + + // JUnit Test Support + testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") + testImplementation("com.google.truth:truth:1.1.4") + testImplementation("org.mockito:mockito-core:5.+") + testImplementation("org.mockito:mockito-junit-jupiter:5.+") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") +} + +// Flattened directory layout +sourceSets { + main { + java { + setSrcDirs(listOf("java")) + } + } + test { + java { + setSrcDirs(listOf("test")) + } + } +} + +tasks.test { + useJUnitPlatform() + jvmArgs = mutableListOf("-Djava.library.path=$projectDir/../../target/debug") +}
diff --git a/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.jar b/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..943f0cb --- /dev/null +++ b/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.jar Binary files differ
diff --git a/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.properties b/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..f398c33 --- /dev/null +++ b/nearby/presence/np_java_ffi/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists
diff --git a/nearby/presence/np_java_ffi/gradlew b/nearby/presence/np_java_ffi/gradlew new file mode 100755 index 0000000..79a61d4 --- /dev/null +++ b/nearby/presence/np_java_ffi/gradlew
@@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@"
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializationException.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializationException.java new file mode 100644 index 0000000..68db2c9 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializationException.java
@@ -0,0 +1,37 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +/** Base class for exceptions that can occur during deserialization. */ +public abstract class DeserializationException extends Exception { + + private DeserializationException(String message) { + super(message); + } + + public static final class InvalidHeaderException extends DeserializationException { + public InvalidHeaderException() { + super("Invalid advertisement header"); + } + } + + public static final class InvalidFormatException extends DeserializationException { + public InvalidFormatException() { + super("Invalid advertisement format"); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializeResult.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializeResult.java new file mode 100644 index 0000000..865df41 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializeResult.java
@@ -0,0 +1,122 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import androidx.annotation.IntDef; +import androidx.annotation.Nullable; +import java.lang.annotation.Retention; + +/** + * A result of calling {@link NpAdv#deserializeAdvertisement}. This represents either an error + * condition or successfully deserialized advertisement. + * + * <p>Note: A successfully deserialized advertisement may still not be legible for cryptographic + * reasons. That condition is reported on the advertisement object itself since a V1 advertisement + * may be partially legible (some sections are legible, not all). + */ +public final class DeserializeResult implements AutoCloseable { + + @IntDef({ + Kind.UNKNOWN_ERROR, + Kind.V0_ADVERTISEMENT, + Kind.V1_ADVERTISEMENT, + }) + @Retention(SOURCE) + public @interface Kind { + public static final int UNKNOWN_ERROR = -1; + + public static final int V0_ADVERTISEMENT = 1; + public static final int V1_ADVERTISEMENT = 2; + } + + /** Checks if a {@link Kind} represents and error or not. */ + public static boolean isErrorKind(@Kind int kind) { + return kind <= 0; + } + + private final @Kind int kind; + private final @Nullable DeserializedAdvertisement advertisement; + + /** Create a DeserializeResult containing an error code */ + /* package */ DeserializeResult(@Kind int errorKind) { + if (!isErrorKind(errorKind)) { + throw new IllegalArgumentException( + "Cannot create empty DeserializeResult with non-error kind"); + } + this.kind = errorKind; + this.advertisement = null; + } + + /** Create a DeserializeResult containing a V0 advertisement */ + /* package */ DeserializeResult(DeserializedV0Advertisement advertisement) { + this.kind = Kind.V0_ADVERTISEMENT; + this.advertisement = advertisement; + } + + /** Create a DeserializeResult containing a V1 advertisement */ + /* package */ DeserializeResult(DeserializedV1Advertisement advertisement) { + this.kind = Kind.V1_ADVERTISEMENT; + this.advertisement = advertisement; + } + + /** Gets the kind of this result. */ + @Kind + public int getKind() { + return kind; + } + + /** Check if this result is an error result. */ + public boolean isError() { + return isErrorKind(kind); + } + + /** + * Gets the contained V0 advertisement if present. + * + * @return the contained V0 advertisement or {@code null} if not present + */ + @Nullable + public DeserializedV0Advertisement getAsV0() { + if (this.kind != Kind.V0_ADVERTISEMENT) { + return null; + } + return (DeserializedV0Advertisement) this.advertisement; + } + + /** + * Gets the contained V1 advertisement if present. + * + * @return the contained V1 advertisement or {@code null} if not present + */ + @Nullable + public DeserializedV1Advertisement getAsV1() { + if (this.kind != Kind.V1_ADVERTISEMENT) { + return null; + } + return (DeserializedV1Advertisement) this.advertisement; + } + + /** Closes the contained advertisement if it exists. */ + @Override + public void close() { + if (this.advertisement != null) { + this.advertisement.close(); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedAdvertisement.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedAdvertisement.java new file mode 100644 index 0000000..2058d8c --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedAdvertisement.java
@@ -0,0 +1,27 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +/** A base class to provide a common type to V0 and V1 advertisements. */ +public abstract class DeserializedAdvertisement implements AutoCloseable { + + /* package */ DeserializedAdvertisement() {} + + // Assert that {@code close()} will not throw checked exceptions. + @Override + public abstract void close(); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV0Advertisement.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV0Advertisement.java new file mode 100644 index 0000000..e4a0688 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV0Advertisement.java
@@ -0,0 +1,155 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import androidx.annotation.Nullable; +import java.util.Iterator; + +/** + * A deserialized V0 advertisement. This class is backed by native data behind the {@link V0Payload} + * handle. If this class is closed then the underlying handle will be closed too. Methods on this + * class should not be called if {@link #close()} has already been called. + */ +public final class DeserializedV0Advertisement extends DeserializedAdvertisement { + + public static boolean isLegibleIdentity(@IdentityKind int identity) { + return identity > 0; + } + + private final int numDataElements; + private final @Nullable V0Payload payload; + private final @IdentityKind int identity; + + /** Create an illegible instance with the given error identity. */ + /* package */ DeserializedV0Advertisement(@IdentityKind int illegibleIdentity) { + if (isLegibleIdentity(illegibleIdentity)) { + throw new IllegalArgumentException( + "Cannot create empty DeserializedV0Advertisement with a legible identity"); + } + this.numDataElements = 0; + this.payload = null; + this.identity = illegibleIdentity; + } + + /** Create a legible instance with the given information. */ + /* package */ DeserializedV0Advertisement( + int numDataElements, V0Payload payload, @IdentityKind int identity) { + this.numDataElements = numDataElements; + this.payload = payload; + this.identity = identity; + } + + /** + * Create a legible instance with the given information. Payload is specified as a raw handle id. + * This is a helper to be called from native code to avoid needing to construct {@code V0Payload} + * on the native side. + */ + /* package */ DeserializedV0Advertisement( + int numDataElements, long payload, @IdentityKind int identity) { + this(numDataElements, new V0Payload(payload), identity); + } + + /** Check if this advertisement is legible */ + public boolean isLegible() { + return isLegibleIdentity(this.identity); + } + + /** Throws {@code IllegalStateException} if this advertisement is not legible. */ + private void ensureLegible(String action) { + if (!isLegible()) { + throw new IllegalStateException( + String.format("Cannot %s for non-legible advertisement", action)); + } + } + + /** + * Gets the identity for this advertisement. + * + * @throws IllegalStateException if the advertisement is not legible ({@link #isLegible()}). + */ + @IdentityKind + public int getIdentity() { + ensureLegible("get identity"); + return this.identity; + } + + /** + * Gets the number of data elements in this advertisement. + * + * @throws IllegalStateException if the advertisement is not legible ({@link #isLegible()}). + */ + public int getDataElementCount() { + ensureLegible("get data element count"); + return this.numDataElements; + } + + /** + * Gets the data element at the given {@code index} in this advertisement. + * + * @param index The data element's index in the advertisement + * @throws IllegalStateException if the advertisement is not legible ({@link #isLegible()}). + * @throws IndexOutOfBoundsException if the index is invalid + * @return The data element at {@code index} + */ + public V0DataElement getDataElement(int index) { + ensureLegible("get data element"); + return payload.getDataElement(index); + } + + /** Gets all the data elements for iteration. */ + public Iterable<V0DataElement> getDataElements() { + return () -> new DataElementIterator(payload, numDataElements); + } + + /** Visits all the data elements with the given visitor. */ + public void visitDataElements(V0DataElement.Visitor v) { + for (V0DataElement de : getDataElements()) { + de.visit(v); + } + } + + /** Iterator instance for data elements in DeserializedV0Advertisement. */ + private static final class DataElementIterator implements Iterator<V0DataElement> { + private final V0Payload payload; + private final int numDataElements; + + private int position = 0; + + public DataElementIterator(V0Payload payload, int numDataElements) { + this.payload = payload; + this.numDataElements = numDataElements; + } + + @Override + public boolean hasNext() { + return position < (numDataElements - 1); + } + + @Override + public V0DataElement next() { + return payload.getDataElement(position++); + } + } + + /** Closes the payload handle if this advertisement is legible. */ + @Override + public void close() { + if (this.payload != null) { + this.payload.close(); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Advertisement.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Advertisement.java new file mode 100644 index 0000000..d1ecdcd --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Advertisement.java
@@ -0,0 +1,97 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import java.util.Iterator; + +/** + * A deserialized V0 advertisement. This class is backed by native data behind the {@link + * LegibleV1Sections} handle. If this class is closed then the underlying handle will be closed too. + * Methods on this class should not be called if {@link #close()} has already been called. + */ +public final class DeserializedV1Advertisement extends DeserializedAdvertisement { + + private final int numLegibleSections; + private final int numUndecryptableSections; + private final LegibleV1Sections legibleSections; + + /** Create a legible instance with the given information. */ + /* package */ DeserializedV1Advertisement( + int numLegibleSections, int numUndecryptableSections, LegibleV1Sections legibleSections) { + this.numLegibleSections = numLegibleSections; + this.numUndecryptableSections = numUndecryptableSections; + this.legibleSections = legibleSections; + } + + /** Get the number of legible sections in this advertisement */ + public int getNumLegibleSections() { + return numLegibleSections; + } + + /** Get the number of undecryptable sections in this advertisement */ + public int getNumUndecryptableSections() { + return numUndecryptableSections; + } + + /** + * Gets the section at the given {@code index} in this advertisement. {@code index} only counts + * legible sections. + * + * @param index The section's index in the advertisement + * @throws IndexOutOfBoundsException if the index is invalid + * @return The section at {@code index} + */ + public DeserializedV1Section getSection(int index) { + return legibleSections.getSection(index); + } + + /** Get an iterable of this advertisement's legible sections. */ + public Iterable<DeserializedV1Section> getSections() { + return () -> new SectionIterator(numLegibleSections, legibleSections); + } + + /** Iterator instance for sections in DeserializedV1Advertisement. */ + private static final class SectionIterator implements Iterator<DeserializedV1Section> { + private final LegibleV1Sections legibleSections; + private final int numSections; + + private int position = 0; + + public SectionIterator(int numSections, LegibleV1Sections legibleSections) { + this.numSections = numSections; + this.legibleSections = legibleSections; + } + + @Override + public boolean hasNext() { + return position < (numSections - 1); + } + + @Override + public DeserializedV1Section next() { + return legibleSections.getSection(position++); + } + } + + /** Closes the legible sections handle if it exists. */ + @Override + public void close() { + if (this.legibleSections != null) { + this.legibleSections.close(); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Section.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Section.java new file mode 100644 index 0000000..1667366 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/DeserializedV1Section.java
@@ -0,0 +1,95 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import java.util.Iterator; + +public final class DeserializedV1Section { + private final LegibleV1Sections legibleSections; + private final int legibleSectionsIndex; + private final int numDataElements; + private final @IdentityKind int identityTag; + + /* package */ DeserializedV1Section( + LegibleV1Sections legibleSections, + int legibleSectionsIndex, + int numDataElements, + @IdentityKind int identityTag) { + this.legibleSections = legibleSections; + this.legibleSectionsIndex = legibleSectionsIndex; + this.numDataElements = numDataElements; + this.identityTag = identityTag; + } + + /** Gets the identity kind for this section. */ + @IdentityKind + public int getIdentityKind() { + return this.identityTag; + } + + /** Gets the number of data elements in this section. */ + public int getDataElementCount() { + return this.numDataElements; + } + + /** + * Gets the data element at the given {@code index} in this advertisement. + * + * @throws IllegalStateException if the advertisement is not legible ({@link #isLegible()}). + * @throws IndexOutOfBoundsException if the index is invalid + */ + public V1DataElement getDataElement(int index) { + return legibleSections.getSectionDataElement(this.legibleSectionsIndex, index); + } + + /** Gets all the data elements for iteration. */ + public Iterable<V1DataElement> getDataElements() { + return () -> new DataElementIterator(legibleSections, legibleSectionsIndex, numDataElements); + } + + /** Visits all the data elements with the given visitor. */ + public void visitDataElements(V1DataElement.Visitor v) { + for (V1DataElement de : getDataElements()) { + de.visit(v); + } + } + + private static final class DataElementIterator implements Iterator<V1DataElement> { + private final LegibleV1Sections legibleSections; + private final int legibleSectionsIndex; + private final int numDataElements; + + private int position = 0; + + public DataElementIterator( + LegibleV1Sections legibleSections, int legibleSectionsIndex, int numDataElements) { + this.legibleSections = legibleSections; + this.legibleSectionsIndex = legibleSectionsIndex; + this.numDataElements = numDataElements; + } + + @Override + public boolean hasNext() { + return position < (numDataElements - 1); + } + + @Override + public V1DataElement next() { + return legibleSections.getSectionDataElement(legibleSectionsIndex, position++); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/Handle.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/Handle.java new file mode 100644 index 0000000..a200358 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/Handle.java
@@ -0,0 +1,45 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +/** + * A handle to a natively-allocated object. This class should be subclassed in order to provide a + * type for the native object. This class does not control the lifetime of the native object. See + * {@link OwnedHandle} for a variant that allows Java to deallocate the native object. + * + * <p>This may be a handle to an object that has already been deallocated. In that case, any native + * uses of this handle should throw {@link Handle.InvalidHandleException}. + */ +public abstract class Handle { + + /** Thrown when an invalid handle is used */ + public static final class InvalidHandleException extends Exception { + public InvalidHandleException() { + super("The given handle is no longer valid"); + } + } + + protected final long handleId; + + protected Handle(long handleId) { + this.handleId = handleId; + } + + public long getId() { + return handleId; + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/IdentityKind.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/IdentityKind.java new file mode 100644 index 0000000..9b69851 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/IdentityKind.java
@@ -0,0 +1,43 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import androidx.annotation.IntDef; +import java.lang.annotation.Retention; + +/** + * The kind of identity that was discovered for a decrypted advertisement. Values greater than + * {@code 0} are legible. Values less than {@code 0} are not. + */ +@IntDef({ + IdentityKind.NO_MATCHING_CREDENTIALS, + IdentityKind.PLAINTEXT, + IdentityKind.DECRYPTED, +}) +@Retention(SOURCE) +public @interface IdentityKind { + /** An encrypted identity that we do not have a credential for. */ + public static final int NO_MATCHING_CREDENTIALS = -1; + + /** A plaintext identity. */ + public static final int PLAINTEXT = 1; + + /** An encrypted identity that we have a credential for. */ + public static final int DECRYPTED = 2; +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/LegibleV1Sections.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/LegibleV1Sections.java new file mode 100644 index 0000000..5175ce6 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/LegibleV1Sections.java
@@ -0,0 +1,80 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import androidx.annotation.Nullable; +import java.lang.ref.Cleaner; + +/** Internal handle for a V1 deserialized advertisement. */ +public final class LegibleV1Sections extends OwnedHandle { + + static { + System.loadLibrary(NpAdv.LIBRARY_NAME); + } + + /** + * Create a LegibleV1Sections handle from the raw handle id. This will use the default cleaner + * form {@code NpAdv#getCleaner()}. This is expected to be called from native code. + */ + /* package-visible */ LegibleV1Sections(long handleId) { + this(handleId, NpAdv.getCleaner()); + } + + /** Create a LegibleV1Sections handle from the raw handle id. */ + /* package-visible */ LegibleV1Sections(long handleId, Cleaner cleaner) { + super(handleId, cleaner, LegibleV1Sections::deallocate); + } + + /** + * Get the section at the given index. + * + * @param index The section's index in the advertisement + * @throws IndexOutOfBoundsException if the given index is out of range for this advertisement + * @return The section at that index + */ + public DeserializedV1Section getSection(int index) { + DeserializedV1Section section = nativeGetSection(index); + if (section == null) { + throw new IndexOutOfBoundsException(); + } + return section; + } + + /** + * Get the data element from a specific section. + * + * @param sectionIndex The section's index in the advertisement. This only counts legible sections + * @param deIndex The data element's index in the section + * @throws IndexOutOfBoundsException if either index is out of range for this advertisement + * @return The data element found at {@code deIndex} in the section at {@code sectionIndex} + */ + public V1DataElement getSectionDataElement(int sectionIndex, int deIndex) { + V1DataElement de = nativeGetSectionDataElement(sectionIndex, deIndex); + if (de == null) { + throw new IndexOutOfBoundsException(); + } + return de; + } + + @Nullable + private native DeserializedV1Section nativeGetSection(int index); + + @Nullable + private native V1DataElement nativeGetSectionDataElement(int sectionIndex, int deIndex); + + private static native void deallocate(long handleId); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/NpAdv.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/NpAdv.java new file mode 100644 index 0000000..21abb89 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/NpAdv.java
@@ -0,0 +1,91 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import androidx.annotation.Nullable; +import com.google.android.nearby.presence.rust.credential.CredentialBook; +import java.lang.ref.Cleaner; + +/** + * The main entrypoint to the library. + * + * <p>On Android call {@link #setCleaner} with a {@code SystemCleaner} instance before any other + * method to avoid creating a new cleaner thread. + * + * <h3>Supported Features:</h3> + * + * <ul> + * <li>Deserialize advertisements: {@link #deserializeAdvertisement} + * </ul> + */ +public final class NpAdv { + + public static final String LIBRARY_NAME = "np_java_ffi"; + + static { + System.loadLibrary(LIBRARY_NAME); + } + + private static @Nullable Cleaner CLEANER = null; + + /** + * Deserialize a Nearby Presence advertisement from its service data bytes. + * + * @param serviceData The service data bytes. Must have length<256. + * @param credentialBook The credential book to use to decrypt. + * @return A result containing the advertisement if it was able to be deserialized. + */ + public static <M extends CredentialBook.MatchedMetadata> + DeserializeResult deserializeAdvertisement( + byte[] serviceData, CredentialBook<M> credentialBook) { + DeserializeResult result = nativeDeserializeAdvertisement(serviceData, credentialBook.getId()); + if (result == null) { + result = new DeserializeResult(DeserializeResult.Kind.UNKNOWN_ERROR); + } + return result; + } + + /** + * Get the currently configured cleaner. If a cleaner is not configured, a new one will be created + * via the {@link Cleaner#create()} factory function. + */ + public static synchronized Cleaner getCleaner() { + if (CLEANER == null) { + CLEANER = Cleaner.create(); + } + return CLEANER; + } + + /** + * Configure a {@link Cleaner} to be used by this library. This cleaner will be used to ensure + * that {@link OwnedHandle} instances are properly freed. Since each {@code Cleaner} instance + * requires its own thread; this can be used to share a {@code Cleaner} instance to reduce the + * number of threads used. + * + * <p>On Android the {@code SystemCleaner} should be provided. + */ + @Nullable + public static synchronized Cleaner setCleaner(Cleaner cleaner) { + Cleaner old = CLEANER; + CLEANER = cleaner; + return old; + } + + @Nullable + private static native DeserializeResult nativeDeserializeAdvertisement( + byte[] serviceData, long credentialBook); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/OwnedHandle.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/OwnedHandle.java new file mode 100644 index 0000000..c505f81 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/OwnedHandle.java
@@ -0,0 +1,129 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import androidx.annotation.Nullable; +import java.lang.ref.Cleaner; + +/** + * A handle to natively-allocated object with lifetime control. This is a {@code Handle} that also + * supports deallocating the native object. + * + * <p>Users should call {@link OwnedHandle#close()} when finished with this handle to free the + * native resources. This can be automatically done when using try-with-resources. If neither are + * use the handle will still be closed when it is garbage collected. + */ +public abstract class OwnedHandle extends Handle implements AutoCloseable { + + /** + * A destructor to be called when this {@link OwnedHandle} is no longer used. + * + * <p>This MUST not hold a reference to the {@link OwnedHandle} instance. Do not implement this on + * your subclass; however, it may be implemented by a method reference to a static method. + */ + public interface Destructor { + void deallocate(long handleId); + } + + /** Thrown when a new handle cannot be allocated due to lack of space */ + public static final class NoSpaceLeftException extends RuntimeException { + public NoSpaceLeftException() { + super("No space remaining in the associated HandleMap"); + } + } + + private final CleanupAction cleanupAction; + + /** + * Create a new instance and register it with the given cleaner. + * + * @param handleId The handle's id + * @param cleaner The cleaner thread to register with for GC cleanup + * @param destructor The destructor to run when this handle is closed + */ + protected OwnedHandle(long handleId, Cleaner cleaner, Destructor destructor) { + super(handleId); + this.cleanupAction = new CleanupAction(handleId, destructor); + + cleaner.register(this, this.cleanupAction); + } + + /** Leak this handle. The associated native object will not be deallocated. */ + protected final void leak() { + this.cleanupAction.leak(); + } + + /** Implement AutoCloseable for try-with-resources support */ + @Override + public final void close() { + this.cleanupAction.cleanupFromCloseable(); + } + + /** + * A {@link Runnable} to be given to the associated {@link Cleaner} to clean up a handle. This + * MUST not hold a reference to the {@link OwnedHandle} that it is associated with. + */ + private static final class CleanupAction implements Runnable { + private final long handleId; + private @Nullable Destructor destructor; + private boolean freed = false; + + public CleanupAction(long handleId, Destructor destructor) { + this.handleId = handleId; + this.destructor = destructor; + } + + /** Skip performing cleanup and leak the object instead */ + private void leak() { + this.destructor = null; + } + + /** + * Deallocate the handle using the given {@link Destructor}. + * + * <p>The Destructor will only be called once, and future calls to this method will return + * {@code false}. + * + * @return {@code true} if the destructor was called. + */ + private boolean deallocate() { + if (this.destructor != null) { + this.destructor.deallocate(this.handleId); + this.destructor = null; + return true; + } + return false; + } + + /** + * Perform the cleanup action. This is separate from {@link #run()} so that we can track if the + * handle was manually closed or if it was cleaned up via the {@link Cleaner}. + */ + public void cleanupFromCloseable() { + if (!deallocate()) { + // FUTURE: log that OwnedHandle#close() was called multiple times. + } + } + + @Override + public void run() { + if (deallocate()) { + // FUTURE: log that OwnedHandle#close() was not called. + } + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0DataElement.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0DataElement.java new file mode 100644 index 0000000..4575f5a --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0DataElement.java
@@ -0,0 +1,114 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import androidx.annotation.IntDef; +import java.lang.annotation.Retention; + +/** Base class for V0 data element types. */ +public abstract class V0DataElement { + + /** + * A visitor interface that can be used while iterating data elements in an advertisement to avoid + * checking {@code instanceof} on every one. + */ + public interface Visitor { + default void visitTxPower(TxPower txPower) {} + + default void visitV0Actions(V0Actions v0Actions) {} + } + + // All subclasses should be in this file + private V0DataElement() {} + + /** Visit this advertisement with the given visitor. */ + public abstract void visit(Visitor v); + + /** Contains the TxPower information. See the spec for more information. */ + public static final class TxPower extends V0DataElement { + private final int txPower; + + public TxPower(int txPower) { + this.txPower = txPower; + } + + public int getTxPower() { + return txPower; + } + + public void visit(Visitor v) { + v.visitTxPower(this); + } + } + + /** Marker annotation/enum for V0 action values. */ + @IntDef({ + V0ActionType.CROSS_DEV_SDK, + V0ActionType.CALL_TRANSFER, + V0ActionType.ACTIVE_UNLOCK, + V0ActionType.NEARBY_SHARE, + V0ActionType.INSTANT_TETHERING, + V0ActionType.PHONE_HUB, + }) + @Retention(SOURCE) + public @interface V0ActionType { + // NOTE: Copied from `np_ffi_core::v0::BooleanActionType`. + public static final int CROSS_DEV_SDK = 1; + public static final int CALL_TRANSFER = 4; + public static final int ACTIVE_UNLOCK = 8; + public static final int NEARBY_SHARE = 9; + public static final int INSTANT_TETHERING = 10; + public static final int PHONE_HUB = 11; + } + + /** The Actions data element. See the spec for more information. */ + public static final class V0Actions extends V0DataElement { + static { + System.loadLibrary(NpAdv.LIBRARY_NAME); + } + + private final @IdentityKind int identityKind; + private final int actionBits; + + public V0Actions(@IdentityKind int identityKind, int actionBits) { + this.identityKind = identityKind; + this.actionBits = actionBits; + } + + @IdentityKind + public int getIdentityKind() { + return identityKind; + } + + public int getActionBits() { + return actionBits; + } + + /** Checks if this Actions DE contains the given action. */ + public boolean hasAction(@V0ActionType int action) { + return nativeHasAction(identityKind, actionBits, action); + } + + public void visit(Visitor v) { + v.visitV0Actions(this); + } + + private static native boolean nativeHasAction(int identityKind, int actionBits, int action); + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0Payload.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0Payload.java new file mode 100644 index 0000000..722f37c --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V0Payload.java
@@ -0,0 +1,64 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import androidx.annotation.Nullable; +import java.lang.ref.Cleaner; + +/** + * Internal handle type for deserialized V0 advertisements. It provides access to the native data + * and allows that data to be deallocated. + */ +public final class V0Payload extends OwnedHandle { + + static { + System.loadLibrary(NpAdv.LIBRARY_NAME); + } + + /** + * Create a V0Payload handle from the raw handle id. This will use the default cleaner form {@code + * NpAdv#getCleaner()}. This is expected to be called from native code. + */ + /* package-visible */ V0Payload(long handleId) { + this(handleId, NpAdv.getCleaner()); + } + + /** Create a V0Payload handle from the raw handle id. */ + /* package-visible */ V0Payload(long handleId, Cleaner cleaner) { + super(handleId, cleaner, V0Payload::deallocate); + } + + /** + * Get the data element at the given index. + * + * @param index The data element's index in the advertisement + * @throws IndexOutOfBoundsException if the given index is out of range for this advertisement + * @return The data element at that index + */ + public V0DataElement getDataElement(int index) { + V0DataElement de = nativeGetDataElement(this.handleId, index); + if (de == null) { + throw new IndexOutOfBoundsException(); + } + return de; + } + + @Nullable + private static native V0DataElement nativeGetDataElement(long handleId, int index); + + private static native void deallocate(long handleId); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V1DataElement.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V1DataElement.java new file mode 100644 index 0000000..b52c7bb --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/V1DataElement.java
@@ -0,0 +1,63 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import java.util.Arrays; + +/** Base class for V1 data element types. */ +public abstract class V1DataElement { + + /** + * A visitor interface that can be used while iterating data elements in an advertisement to avoid + * checking {@code instanceof} on every one. + */ + public interface Visitor { + void visitGeneric(Generic generic); + } + + // All subclasses should be in this file + private V1DataElement() {} + + /** Visit this advertisement with the given visitor. */ + public abstract void visit(Visitor v); + + /** + * A generic data element. This is a data element which has a type that is not known by this + * library (e.g. a vendor-specific data element). + */ + public static final class Generic extends V1DataElement { + private final long type; + private final byte[] data; + + public Generic(long type, byte[] data) { + this.type = type; + this.data = Arrays.copyOf(data, data.length); + } + + public long getType() { + return type; + } + + public byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + public void visit(Visitor v) { + v.visitGeneric(this); + } + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialBook.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialBook.java new file mode 100644 index 0000000..cdcc50b --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialBook.java
@@ -0,0 +1,140 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import com.google.android.nearby.presence.rust.NpAdv; +import com.google.android.nearby.presence.rust.OwnedHandle; +import java.lang.ref.Cleaner; +import java.util.ArrayList; + +public final class CredentialBook<M extends CredentialBook.MatchedMetadata> extends OwnedHandle { + + static { + System.loadLibrary(NpAdv.LIBRARY_NAME); + } + + /** Metadata that is associated with a Credential. */ + public interface MatchedMetadata { + /** + * Get the bytes for encrypted metadata. This byte array may be empty if there is no encrypted + * metadata. + */ + byte[] getEncryptedMetadataBytes(); + } + + /** {@link MatchedMetadata} implementation for cases where there is no associated metadata. */ + public static class NoMetadata implements MatchedMetadata { + + /** An instance to avoid needing additional instances of this class. */ + public static final NoMetadata INSTANCE = new NoMetadata(); + + @Override + public byte[] getEncryptedMetadataBytes() { + return new byte[0]; + } + } + + /** Thrown when a cryptographic key is given and those key bytes are not valid. */ + public static final class InvalidPublicKeyException extends RuntimeException { + public InvalidPublicKeyException() { + super( + "The provided public key bytes do not actually represent a valid \"edwards y\" format or" + + " that said compressed point is not actually a point on the curve."); + } + } + + /** Builder for {@code CredentialBook} */ + public static final class Builder<M extends MatchedMetadata> { + private Cleaner cleaner; + private CredentialSlab slab; + + // Each credential should be given an id of its metadata index so that this array is an + // id-to-metadata map. + private ArrayList<M> matchDataList; + + /** + * Create a builder instance. The {@link CredentialBook#builder()} factory method can be used to + * create a {@code Builder} with the default {@link Cleaner}. This can fail if there isn't room + * to create a new {@code CredentialSlab} handle. + * + * @param cleaner The cleaner instance to use for the {@link CredentialSlab} and {@code + * CredentialBook}. + */ + public Builder(Cleaner cleaner) { + this.cleaner = cleaner; + this.slab = new CredentialSlab(cleaner); + this.matchDataList = new ArrayList<>(); + } + + /** Add a {@link V0DiscoveryCredential} to the book. */ + public Builder<M> addDiscoveryCredential(V0DiscoveryCredential credential, M matchData) { + int credIdx = matchDataList.size(); + matchDataList.add(matchData); + slab.addDiscoveryCredential(credential, credIdx, matchData.getEncryptedMetadataBytes()); + return this; + } + + /** + * Add a {@link V1DiscoveryCredential} to the book. May throw {@link + * CredentialBook.InvalidPublicKeyException} if the key inside {@code credential} is improperly + * formatted. + */ + public Builder<M> addDiscoveryCredential(V1DiscoveryCredential credential, M matchData) { + int credIdx = matchDataList.size(); + matchDataList.add(matchData); + slab.addDiscoveryCredential(credential, credIdx, matchData.getEncryptedMetadataBytes()); + return this; + } + + /** + * Create the {@code CredentialBook}. This can fail if there isn't room to create a new {@code + * CredentialBook} handle. + */ + public CredentialBook<M> build() { + return new CredentialBook(slab, matchDataList, cleaner); + } + } + + /** Create a credential book builder with the default cleaner from {@link NpAdv#getCleaner()}. */ + public static <M extends MatchedMetadata> Builder<M> builder() { + return new Builder<M>(NpAdv.getCleaner()); + } + + /** + * Create an empty credential book. This is useful for when only plaintext advertisements are + * being deserialized. + */ + public static CredentialBook<NoMetadata> empty() { + return new Builder<NoMetadata>(NpAdv.getCleaner()).build(); + } + + private final ArrayList<M> matchData; + + /** + * Create a new credential book. This always consumes the slab handle. This should only be called + * from {@code Builder}. {@code matchData} is formatted so that each credential is given an id of + * the index of its metadata in {@code matchData}. + */ + private CredentialBook(CredentialSlab slab, ArrayList<M> matchData, Cleaner cleaner) { + super(allocate(slab.move()), cleaner, CredentialBook::deallocate); + this.matchData = matchData; + } + + private static native long allocate(long slabHandleId); + + private static native void deallocate(long handleId); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialSlab.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialSlab.java new file mode 100644 index 0000000..35fc610 --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/CredentialSlab.java
@@ -0,0 +1,71 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import com.google.android.nearby.presence.rust.NpAdv; +import com.google.android.nearby.presence.rust.OwnedHandle; +import java.lang.ref.Cleaner; + +/** + * A {@code CredentialSlab} handle that is used to build the native-side structures for a {@link + * CredentialBook}. Clients should use {@link CredentialSlab.Builder} instead of this class. + */ +final class CredentialSlab extends OwnedHandle { + static { + System.loadLibrary(NpAdv.LIBRARY_NAME); + } + + /** Create a new {@code CredentialSlab} with the given {@code cleaner}. */ + public CredentialSlab(Cleaner cleaner) { + super(allocate(), cleaner, CredentialSlab::deallocate); + } + + /** Add a V0 discovery credential to this slab. */ + public void addDiscoveryCredential( + V0DiscoveryCredential credential, int credId, byte[] encryptedMetadataBytes) { + nativeAddV0DiscoveryCredential(handleId, credential, credId, encryptedMetadataBytes); + } + + /** + * Add a V1 discovery credential to this slab. May throw {@link + * CredentialBook.InvalidKeyException} if the key inside {@code credential} is improperly + * formatted. + */ + public void addDiscoveryCredential( + V1DiscoveryCredential credential, int credId, byte[] encryptedMetadataBytes) { + nativeAddV1DiscoveryCredential(handleId, credential, credId, encryptedMetadataBytes); + } + + /** + * Mark this slab handle as moved and return the handle id. This will leak the handle. This should + * be done when the handle is moved to the Rust side to avoid freeing it early. + */ + public long move() { + leak(); + return handleId; + } + + private static native long allocate(); + + private static native boolean nativeAddV0DiscoveryCredential( + long handleId, V0DiscoveryCredential cred, int credId, byte[] encryptedMetadataBytes); + + private static native boolean nativeAddV1DiscoveryCredential( + long handleId, V1DiscoveryCredential cred, int credId, byte[] encryptedMetadataBytes); + + private static native void deallocate(long handleId); +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/Utils.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/Utils.java new file mode 100644 index 0000000..c38bbcf --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/Utils.java
@@ -0,0 +1,35 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import java.util.Arrays; + +/** Util functions used by multiple files. */ +final class Utils { + + /** + * Create a copy of a 32-byte array of key data. Will throw {@code IllegalArgumentException} if + * the array is not exactly 32 bytes. + */ + public static byte[] copyKeyBytes(byte[] key) { + if (key.length != 32) { + throw new IllegalArgumentException( + String.format("Expected key length to be 32 bytes, got %s bytes", key.length)); + } + return Arrays.copyOf(key, key.length); + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V0DiscoveryCredential.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V0DiscoveryCredential.java new file mode 100644 index 0000000..be8734b --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V0DiscoveryCredential.java
@@ -0,0 +1,31 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import static com.google.android.nearby.presence.rust.credential.Utils.copyKeyBytes; + +/** A V0 discovery credential in a format that is ready to be passed to native code. */ +public final class V0DiscoveryCredential { + private final byte[] keySeed; + private final byte[] identityTokenHmac; + + /** Create the credential. Each array is exactly 32 bytes. */ + public V0DiscoveryCredential(byte[] keySeed, byte[] identityTokenHmac) { + this.keySeed = copyKeyBytes(keySeed); + this.identityTokenHmac = copyKeyBytes(identityTokenHmac); + } +}
diff --git a/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V1DiscoveryCredential.java b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V1DiscoveryCredential.java new file mode 100644 index 0000000..c2afefa --- /dev/null +++ b/nearby/presence/np_java_ffi/java/com/google/android/nearby/presence/rust/credential/V1DiscoveryCredential.java
@@ -0,0 +1,44 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import static com.google.android.nearby.presence.rust.credential.Utils.copyKeyBytes; + +/** A V1 discovery credential in a format that is ready to be passed to native code. */ +public final class V1DiscoveryCredential { + private final byte[] keySeed; + private final byte[] expectedMicShortSaltIdentityTokenHmac; + private final byte[] expectedMicExtendedSaltIdentityTokenHmac; + private final byte[] expectedSignatureIdentityTokenHmac; + private final byte[] pubKey; + + /** Create the credential. Each array is exactly 32 bytes. */ + public V1DiscoveryCredential( + byte[] keySeed, + byte[] expectedMicShortSaltIdentityTokenHmac, + byte[] expectedMicExtendedSaltIdentityTokenHmac, + byte[] expectedSignatureIdentityTokenHmac, + byte[] pubKey) { + this.keySeed = copyKeyBytes(keySeed); + this.expectedMicShortSaltIdentityTokenHmac = + copyKeyBytes(expectedMicShortSaltIdentityTokenHmac); + this.expectedMicExtendedSaltIdentityTokenHmac = + copyKeyBytes(expectedMicExtendedSaltIdentityTokenHmac); + this.expectedSignatureIdentityTokenHmac = copyKeyBytes(expectedSignatureIdentityTokenHmac); + this.pubKey = copyKeyBytes(pubKey); + } +}
diff --git a/nearby/presence/np_java_ffi/settings.gradle.kts b/nearby/presence/np_java_ffi/settings.gradle.kts new file mode 100644 index 0000000..0c9915a --- /dev/null +++ b/nearby/presence/np_java_ffi/settings.gradle.kts
@@ -0,0 +1,17 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +rootProject.name = "np-java-ffi"
diff --git a/nearby/presence/np_java_ffi/src/class.rs b/nearby/presence/np_java_ffi/src/class.rs new file mode 100644 index 0000000..9c07137 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class.rs
@@ -0,0 +1,62 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Rust wrappers for Java classes. +//! +//! The pattern being used here it to create a new wrapper type for each Java class being used by +//! this library. Each wrapper type will implement the required accessors for its members so that +//! JNI code using a member can be easily found in case that member is changed. Native methods will +//! also be implemented along side the wrapper of the class they are implementing. +//! +//! This library is primarily meant to be used from Java. The Java entrypoint to this library is +//! `class NpAdv`. + +use jni::JNIEnv; + +/// Trait to allow Java exceptions to be thrown from rust Errors +pub trait ToJavaException { + /// Convert this error to a Java exception and throw it. + fn throw_java_exception<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()>; +} + +mod credential_book; +mod credential_slab; +mod deserialization_exception; +mod deserialize_result; +mod deserialized_v0_advertisement; +mod deserialized_v1_advertisement; +mod deserialized_v1_section; +mod handle; +mod identity_kind; +mod legible_v1_sections; +mod np_adv; +mod owned_handle; +mod v0_discovery_credential; +mod v0_payload; +mod v1_discovery_credential; + +pub mod v0_data_element; +pub mod v1_data_element; + +pub use deserialization_exception::{InvalidFormatException, InvalidHeaderException}; +pub use deserialize_result::{DeserializeResult, DeserializeResultError}; +pub use deserialized_v0_advertisement::{DeserializedV0Advertisement, V0AdvertisementError}; +pub use deserialized_v1_advertisement::DeserializedV1Advertisement; +pub use deserialized_v1_section::DeserializedV1Section; +pub use handle::InvalidHandleException; +pub use identity_kind::IdentityKind; +pub use legible_v1_sections::LegibleV1Sections; +pub use owned_handle::NoSpaceLeftException; +pub use v0_discovery_credential::V0DiscoveryCredential; +pub use v1_discovery_credential::V1DiscoveryCredential;
diff --git a/nearby/presence/np_java_ffi/src/class/credential_book.rs b/nearby/presence/np_java_ffi/src/class/credential_book.rs new file mode 100644 index 0000000..ea371da --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/credential_book.rs
@@ -0,0 +1,65 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{objects::JClass, sys::jlong, JNIEnv}; + +use crate::class::{InvalidHandleException, NoSpaceLeftException}; +use handle_map::{Handle, HandleLike}; +use np_ffi_core::credentials::{ + create_credential_book_from_slab, deallocate_credential_book, CreateCredentialBookResult, + CredentialBook, CredentialSlab, +}; +use pourover::jni_method; + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialBook", + method_name = "allocate" +)] +extern "system" fn allocate_book<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + slab_handle_id: jlong, +) -> jlong { + let slab = CredentialSlab::from_handle(Handle::from_id(slab_handle_id as u64)); + + match create_credential_book_from_slab(slab) { + CreateCredentialBookResult::Success(handle) => handle.get_as_handle().get_id() as jlong, + CreateCredentialBookResult::InvalidSlabHandle => { + let _ = InvalidHandleException::throw_new(&mut env); + 0 + } + CreateCredentialBookResult::NoSpaceLeft => { + // Make sure slab is consumed. + let _ = slab.deallocate(); + let _ = NoSpaceLeftException::throw_new(&mut env); + 0 + } + } +} + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialBook", + method_name = "deallocate" +)] +extern "system" fn deallocate_book<'local>( + _env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, +) { + // Swallow errors here since there's nothing meaningful to do. + let _ = + deallocate_credential_book(CredentialBook::from_handle(Handle::from_id(handle_id as u64))); +}
diff --git a/nearby/presence/np_java_ffi/src/class/credential_slab.rs b/nearby/presence/np_java_ffi/src/class/credential_slab.rs new file mode 100644 index 0000000..7e8f37d --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/credential_slab.rs
@@ -0,0 +1,160 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JByteArray, JClass, JObject, JThrowable}, + sys::{jboolean, jint, jlong, JNI_FALSE, JNI_TRUE}, + JNIEnv, +}; + +use crate::class::{ + InvalidHandleException, NoSpaceLeftException, V0DiscoveryCredential, V1DiscoveryCredential, +}; +use handle_map::Handle; +use np_ffi_core::credentials::{ + create_credential_slab, deallocate_credential_slab, AddV0CredentialToSlabResult, + AddV1CredentialToSlabResult, CreateCredentialSlabResult, CredentialSlab, MatchedCredential, +}; +use pourover::{desc::ClassDesc, jni_method}; + +static INVALID_KEY_EXCEPTION_CLASS: ClassDesc = ClassDesc::new( + "com/google/android/nearby/presence/rust/credential/CredentialBook$InvalidPublicKeyException", +); + +/// Rust representation of `class InvalidPublicKeyException`. +#[repr(transparent)] +pub struct InvalidPublicKeyException<Obj>(pub Obj); + +impl<'local> InvalidPublicKeyException<JObject<'local>> { + /// Create a new instance. + pub fn construct(env: &mut JNIEnv<'local>) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &INVALID_KEY_EXCEPTION_CLASS, "()V").map(Self) + } + + /// Create a new instance and throw it. + pub fn throw_new(env: &mut JNIEnv<'local>) -> jni::errors::Result<()> { + Self::construct(env)?.throw(env) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> InvalidPublicKeyException<Obj> { + /// Throw this exception. + pub fn throw<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + env.throw(<&JThrowable>::from(self.0.as_ref())) + } +} + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialSlab", + method_name = "allocate" +)] +extern "system" fn allocate_slab<'local>(mut env: JNIEnv<'local>, _cls: JClass<'local>) -> jlong { + let CreateCredentialSlabResult::Success(slab) = create_credential_slab() else { + let _ = NoSpaceLeftException::throw_new(&mut env); + return 0; + }; + + slab.get_as_handle().get_id() as jlong +} + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialSlab" +)] +extern "system" fn nativeAddV0DiscoveryCredential<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, + credential: V0DiscoveryCredential<JObject<'local>>, + cred_id: jint, + encrypted_metadata_bytes: JByteArray<'local>, +) -> jboolean { + let mut add_cred = move || { + let slab = CredentialSlab::from_handle(Handle::from_id(handle_id as u64)); + + let core_cred = credential.get_as_core(&mut env)?; + let match_data = MatchedCredential::from_arc_bytes( + cred_id as u32, + env.convert_byte_array(&encrypted_metadata_bytes)?.into(), + ); + + Ok::<_, jni::errors::Error>(match slab.add_v0(core_cred, match_data) { + AddV0CredentialToSlabResult::Success => JNI_TRUE, + AddV0CredentialToSlabResult::InvalidHandle => { + InvalidHandleException::throw_new(&mut env)?; + JNI_FALSE + } + }) + }; + + match add_cred() { + Ok(ret) => ret, + Err(_) => JNI_FALSE, + } +} + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialSlab" +)] +extern "system" fn nativeAddV1DiscoveryCredential<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, + credential: V1DiscoveryCredential<JObject<'local>>, + cred_id: jint, + encrypted_metadata_bytes: JByteArray<'local>, +) -> jboolean { + let mut add_cred = move || { + let slab = CredentialSlab::from_handle(Handle::from_id(handle_id as u64)); + + let core_cred = credential.get_as_core(&mut env)?; + let match_data = MatchedCredential::from_arc_bytes( + cred_id as u32, + env.convert_byte_array(&encrypted_metadata_bytes)?.into(), + ); + + Ok::<_, jni::errors::Error>(match slab.add_v1(core_cred, match_data) { + AddV1CredentialToSlabResult::Success => JNI_TRUE, + AddV1CredentialToSlabResult::InvalidHandle => { + InvalidHandleException::throw_new(&mut env)?; + JNI_FALSE + } + AddV1CredentialToSlabResult::InvalidPublicKeyBytes => { + InvalidPublicKeyException::throw_new(&mut env)?; + JNI_FALSE + } + }) + }; + + match add_cred() { + Ok(ret) => ret, + Err(_) => JNI_FALSE, + } +} + +#[jni_method( + package = "com.google.android.nearby.presence.rust.credential", + class = "CredentialSlab", + method_name = "deallocate" +)] +extern "system" fn deallocate_slab<'local>( + _env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, +) { + let slab = CredentialSlab::from_handle(Handle::from_id(handle_id as u64)); + let _ = deallocate_credential_slab(slab); +}
diff --git a/nearby/presence/np_java_ffi/src/class/deserialization_exception.rs b/nearby/presence/np_java_ffi/src/class/deserialization_exception.rs new file mode 100644 index 0000000..a48c515 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/deserialization_exception.rs
@@ -0,0 +1,86 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JObject, JThrowable}, + JNIEnv, +}; +use np_adv::AdvDeserializationError; +use pourover::desc::ClassDesc; + +static INVALID_HEADER_CLASS: ClassDesc = ClassDesc::new( + "com/google/android/nearby/presence/rust/DeserializationException$InvalidHeaderException", +); + +/// Rust representation of `class DeserializationException.InvalidHeaderException`. +#[repr(transparent)] +pub struct InvalidHeaderException<Obj>(pub Obj); + +impl<'local> InvalidHeaderException<JObject<'local>> { + /// Create a new instance. + pub fn construct(env: &mut JNIEnv<'local>) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &INVALID_HEADER_CLASS, "()V").map(Self) + } + + /// Create a new instance and throw it. + pub fn throw_new(env: &mut JNIEnv<'local>) -> jni::errors::Result<()> { + Self::construct(env)?.throw(env) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> InvalidHeaderException<Obj> { + /// Throw this exception. + pub fn throw<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + env.throw(<&JThrowable>::from(self.0.as_ref())) + } +} + +static INVALID_FORMAT_CLASS: ClassDesc = ClassDesc::new( + "com/google/android/nearby/presence/rust/DeserializationException$InvalidFormatException", +); + +/// Rust representation of `class DeserializationException.InvalidFormatException`. +#[repr(transparent)] +pub struct InvalidFormatException<Obj>(pub Obj); + +impl<'local> InvalidFormatException<JObject<'local>> { + /// Create a new instance. + pub fn construct(env: &mut JNIEnv<'local>) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &INVALID_FORMAT_CLASS, "()V").map(Self) + } + + /// Create a new instance and throw it. + pub fn throw_new(env: &mut JNIEnv<'local>) -> jni::errors::Result<()> { + Self::construct(env)?.throw(env) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> InvalidFormatException<Obj> { + /// Throw this exception. + pub fn throw<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + env.throw(<&JThrowable>::from(self.0.as_ref())) + } +} + +/// Allow AdvDeserializationError to be thrown as a Java exception. +impl super::ToJavaException for AdvDeserializationError { + fn throw_java_exception<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + match *self { + AdvDeserializationError::VersionHeaderParseError => { + InvalidHeaderException::throw_new(env) + } + AdvDeserializationError::ParseError { .. } => InvalidFormatException::throw_new(env), + } + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/deserialize_result.rs b/nearby/presence/np_java_ffi/src/class/deserialize_result.rs new file mode 100644 index 0000000..a38df0f --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/deserialize_result.rs
@@ -0,0 +1,103 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::JObject, + signature::{JavaType, Primitive}, + sys::jint, + JNIEnv, +}; +use pourover::desc::{ClassDesc, StaticFieldDesc}; + +use crate::class::{DeserializedV0Advertisement, DeserializedV1Advertisement}; + +static DESERIALIZE_RESULT_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/DeserializeResult"); + +/// Rust representation of `class DeserializeResult`. +#[repr(transparent)] +pub struct DeserializeResult<Obj>(pub Obj); + +impl<'local> DeserializeResult<JObject<'local>> { + /// Create a result representing the given error. + pub fn construct_from_error( + env: &mut JNIEnv<'local>, + error: DeserializeResultError, + ) -> jni::errors::Result<Self> { + let error = error.lookup_java_value(env)?; + pourover::call_constructor!(env, &DESERIALIZE_RESULT_CLASS, "(I)V", error).map(Self) + } + + /// Create a result containing the given advertisement. + pub fn from_v0_advertisement( + env: &mut JNIEnv<'local>, + adv: DeserializedV0Advertisement<impl AsRef<JObject<'local>>>, + ) -> jni::errors::Result<Self> { + pourover::call_constructor!( + env, + &DESERIALIZE_RESULT_CLASS, + "(Lcom/google/android/nearby/presence/rust/DeserializedV0Advertisement;)V", + adv.as_obj() + ) + .map(Self) + } + + /// Create a result containing the given advertisement. + pub fn from_v1_advertisement( + env: &mut JNIEnv<'local>, + adv: DeserializedV1Advertisement<impl AsRef<JObject<'local>>>, + ) -> jni::errors::Result<Self> { + pourover::call_constructor!( + env, + &DESERIALIZE_RESULT_CLASS, + "(Lcom/google/android/nearby/presence/rust/DeserializedV1Advertisement;)V", + adv.as_obj() + ) + .map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> DeserializeResult<Obj> { + /// Get a reference to the inner `jni` crate [`JObject`]. + pub fn as_obj(&self) -> &JObject<'local> { + self.0.as_ref() + } +} + +static DESERIALIZE_RESULT_KIND_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/DeserializeResult$Kind"); + +/// An error that occurs during deserialization +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum DeserializeResultError { + /// An unspecified error has occurred. + UnknownError, +} + +impl DeserializeResultError { + /// Fetch the Java `@IntDef` value for this error. + fn lookup_java_value(&self, env: &mut JNIEnv<'_>) -> jni::errors::Result<jint> { + static UNKNOWN_ERROR_STATIC_FIELD: StaticFieldDesc = + DESERIALIZE_RESULT_KIND_CLASS.static_field("UNKNOWN_ERROR", "I"); + match self { + DeserializeResultError::UnknownError => env + .get_static_field_unchecked( + UNKNOWN_ERROR_STATIC_FIELD.cls(), + &UNKNOWN_ERROR_STATIC_FIELD, + JavaType::Primitive(Primitive::Int), + ) + .and_then(|ret| ret.i()), + } + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/deserialized_v0_advertisement.rs b/nearby/presence/np_java_ffi/src/class/deserialized_v0_advertisement.rs new file mode 100644 index 0000000..1d91ae9 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/deserialized_v0_advertisement.rs
@@ -0,0 +1,79 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::JObject, + sys::{jint, jlong}, + JNIEnv, +}; +use np_ffi_core::deserialize::v0::{DeserializedV0IdentityKind, V0Payload}; +use pourover::desc::ClassDesc; + +use crate::class::IdentityKind; + +static DESERIALIZED_V0_ADVERTISEMENT_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/DeserializedV0Advertisement"); + +/// Rust representation of `class DeserializedV0Advertisement`. +#[repr(transparent)] +pub struct DeserializedV0Advertisement<Obj>(pub Obj); + +impl<'local> DeserializedV0Advertisement<JObject<'local>> { + /// Create an illegible advertisment with the given error. + pub fn construct_from_error( + env: &mut JNIEnv<'local>, + error: V0AdvertisementError, + ) -> jni::errors::Result<Self> { + let error = IdentityKind::error_for_v0(env, error)?; + + pourover::call_constructor!(env, &DESERIALIZED_V0_ADVERTISEMENT_CLASS, "(I)V", error) + .map(Self) + } + + /// Create a legible advertisment. + pub fn construct( + env: &mut JNIEnv<'local>, + num_des: u8, + v0_payload: V0Payload, + identity: DeserializedV0IdentityKind, + ) -> jni::errors::Result<Self> { + let num_des = jint::from(num_des); + let payload_handle = v0_payload.get_as_handle().get_id() as jlong; + let identity = IdentityKind::value_for_v0(env, identity)?; + + pourover::call_constructor!( + env, + &DESERIALIZED_V0_ADVERTISEMENT_CLASS, + "(IJI)V", + num_des, + payload_handle, + identity + ) + .map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> DeserializedV0Advertisement<Obj> { + /// Get a reference to the inner `jni` crate [`JObject`]. + pub fn as_obj(&self) -> &JObject<'local> { + self.0.as_ref() + } +} + +/// A reason for an advertisment being illegible +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum V0AdvertisementError { + /// There is no matching credential in the credential book. + NoMatchingCredentials, +}
diff --git a/nearby/presence/np_java_ffi/src/class/deserialized_v1_advertisement.rs b/nearby/presence/np_java_ffi/src/class/deserialized_v1_advertisement.rs new file mode 100644 index 0000000..e537052 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/deserialized_v1_advertisement.rs
@@ -0,0 +1,50 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{objects::JObject, sys::jint, JNIEnv}; +use pourover::desc::ClassDesc; + +static DESERIALIZED_V1_ADVERTISEMENT_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/DeserializedV1Advertisement"); + +/// Rust representation of `class DeserializedV1Advertisement`. +#[repr(transparent)] +pub struct DeserializedV1Advertisement<Obj>(pub Obj); + +impl<'local> DeserializedV1Advertisement<JObject<'local>> { + /// Create a new advertisement. + pub fn construct( + env: &mut JNIEnv<'local>, + num_legible_sections: jint, + num_undecryptable_sections: jint, + legible_sections: super::LegibleV1Sections<impl AsRef<JObject<'local>>>, + ) -> jni::errors::Result<Self> { + pourover::call_constructor!( + env, + &DESERIALIZED_V1_ADVERTISEMENT_CLASS, + "(IILcom/google/android/nearby/presence/rust/LegibleV1Sections;)V", + num_legible_sections, + num_undecryptable_sections, + legible_sections.as_obj() + ) + .map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> DeserializedV1Advertisement<Obj> { + /// Get a reference to the inner `jni` crate [`JObject`]. + pub fn as_obj(&self) -> &JObject<'local> { + self.0.as_ref() + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/deserialized_v1_section.rs b/nearby/presence/np_java_ffi/src/class/deserialized_v1_section.rs new file mode 100644 index 0000000..b3f6dba --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/deserialized_v1_section.rs
@@ -0,0 +1,50 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{objects::JObject, sys::jint, JNIEnv}; +use np_ffi_core::deserialize::v1::DeserializedV1IdentityKind; +use pourover::desc::ClassDesc; + +use crate::class::{IdentityKind, LegibleV1Sections}; + +static DESERIALIZED_V1_SECTION_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/DeserializedV1Section"); + +/// Rust representation of `class DeserializedV1Section`. +#[repr(transparent)] +pub struct DeserializedV1Section<Obj>(pub Obj); + +impl<'local> DeserializedV1Section<JObject<'local>> { + /// Create a new deserialized section + pub fn construct<'a>( + env: &mut JNIEnv<'local>, + legible_sections_handle: LegibleV1Sections<impl AsRef<JObject<'a>>>, + legible_section_index: u8, + num_des: u8, + identity_kind: DeserializedV1IdentityKind, + ) -> jni::errors::Result<Self> { + let identity = IdentityKind::value_for_v1(env, identity_kind)?; + + pourover::call_constructor!( + env, + &DESERIALIZED_V1_SECTION_CLASS, + "(Lcom/google/android/nearby/presence/rust/LegibleV1Sections;III)V", + legible_sections_handle.as_obj(), + jint::from(legible_section_index), + jint::from(num_des), + identity + ) + .map(Self) + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/handle.rs b/nearby/presence/np_java_ffi/src/class/handle.rs new file mode 100644 index 0000000..7505507 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/handle.rs
@@ -0,0 +1,45 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JObject, JThrowable}, + JNIEnv, +}; +use pourover::desc::ClassDesc; + +static INVALID_HANDLE_EXCEPTION_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/Handle$InvalidHandleException"); + +/// Rust representation of `class InvalidHandleException`. +#[repr(transparent)] +pub struct InvalidHandleException<Obj>(pub Obj); + +impl<'local> InvalidHandleException<JObject<'local>> { + /// Create a new instance. + pub fn construct(env: &mut JNIEnv<'local>) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &INVALID_HANDLE_EXCEPTION_CLASS, "()V").map(Self) + } + + /// Create a new instance and throw it. + pub fn throw_new(env: &mut JNIEnv<'local>) -> jni::errors::Result<()> { + Self::construct(env)?.throw(env) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> InvalidHandleException<Obj> { + /// Throw this exception. + pub fn throw<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + env.throw(<&JThrowable>::from(self.0.as_ref())) + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/identity_kind.rs b/nearby/presence/np_java_ffi/src/class/identity_kind.rs new file mode 100644 index 0000000..8fce071 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/identity_kind.rs
@@ -0,0 +1,117 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + signature::{JavaType, Primitive}, + sys::jint, + JNIEnv, +}; +use np_ffi_core::deserialize::{v0::DeserializedV0IdentityKind, v1::DeserializedV1IdentityKind}; +use pourover::desc::{ClassDesc, StaticFieldDesc}; +use std::sync::RwLock; + +use crate::class::V0AdvertisementError; + +static IDENTITY_KIND_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/IdentityKind"); + +/// Rust representation of `@IdentityKind`. These are `jints` on the Java side, so this type can't +/// be instantiated. +pub enum IdentityKind {} + +impl IdentityKind { + /// Fetch the `NO_MATCHING_CREDENTIALS` constant + pub fn no_matching_credentials<'local>(env: &mut JNIEnv<'local>) -> jni::errors::Result<jint> { + static NO_MATCHING_CREDENTIALS: StaticFieldDesc = + IDENTITY_KIND_CLASS.static_field("NO_MATCHING_CREDENTIALS", "I"); + static VALUE: RwLock<Option<jint>> = RwLock::new(None); + Self::lookup_static_value(env, &NO_MATCHING_CREDENTIALS, &VALUE) + } + + /// Fetch the `PLAINTEXT` constant + pub fn plaintext<'local>(env: &mut JNIEnv<'local>) -> jni::errors::Result<jint> { + static PLAINTEXT: StaticFieldDesc = IDENTITY_KIND_CLASS.static_field("PLAINTEXT", "I"); + static VALUE: RwLock<Option<jint>> = RwLock::new(None); + Self::lookup_static_value(env, &PLAINTEXT, &VALUE) + } + + /// Fetch the `DECRYPTED` constant + pub fn decrypted<'local>(env: &mut JNIEnv<'local>) -> jni::errors::Result<jint> { + static DECRYPTED: StaticFieldDesc = IDENTITY_KIND_CLASS.static_field("DECRYPTED", "I"); + static VALUE: RwLock<Option<jint>> = RwLock::new(None); + Self::lookup_static_value(env, &DECRYPTED, &VALUE) + } + + /// Look up the given field and cache it in the given cache. The lookup will only be performed + /// once if successful. This uses `RwLock` instead of `OnceCell` since the fallible `OnceCell` + /// APIs are nightly only. + fn lookup_static_value<'local>( + env: &mut JNIEnv<'local>, + field: &StaticFieldDesc, + cache: &RwLock<Option<jint>>, + ) -> jni::errors::Result<jint> { + // Read from cache + if let Some(value) = *cache.read().unwrap_or_else(|poison| poison.into_inner()) { + return Ok(value); + } + + // Get exclusive access to the cache for the lookup + let mut guard = cache.write().unwrap_or_else(|poison| poison.into_inner()); + + // In case of races, only lookup the value once + if let Some(value) = *guard { + return Ok(value); + } + + let value = env + .get_static_field_unchecked(field.cls(), field, JavaType::Primitive(Primitive::Int)) + .and_then(|ret| ret.i())?; + + *guard = Some(value); + + Ok(value) + } + + /// Get the Java representation of [`V0AdvertisementError`]. + pub fn error_for_v0<'local>( + env: &mut JNIEnv<'local>, + identity: V0AdvertisementError, + ) -> jni::errors::Result<jint> { + match identity { + V0AdvertisementError::NoMatchingCredentials => Self::no_matching_credentials(env), + } + } + + /// Get the Java representation of [`DeserializedV0IdentityKind`]. + pub fn value_for_v0<'local>( + env: &mut JNIEnv<'local>, + identity: DeserializedV0IdentityKind, + ) -> jni::errors::Result<jint> { + match identity { + DeserializedV0IdentityKind::Plaintext => Self::plaintext(env), + DeserializedV0IdentityKind::Decrypted => Self::decrypted(env), + } + } + + /// Get the Java representation of [`DeserializedV1IdentityKind`]. + pub fn value_for_v1<'local>( + env: &mut JNIEnv<'local>, + identity: DeserializedV1IdentityKind, + ) -> jni::errors::Result<jint> { + match identity { + DeserializedV1IdentityKind::Plaintext => Self::plaintext(env), + DeserializedV1IdentityKind::Decrypted => Self::decrypted(env), + } + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/legible_v1_sections.rs b/nearby/presence/np_java_ffi/src/class/legible_v1_sections.rs new file mode 100644 index 0000000..911c78d --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/legible_v1_sections.rs
@@ -0,0 +1,159 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JClass, JObject}, + sys::{jint, jlong}, + JNIEnv, +}; + +use crate::class::{v1_data_element::Generic, DeserializedV1Section}; +use handle_map::{Handle, HandleLike}; +use np_ffi_core::deserialize::v1::{ + GetV1DEResult, GetV1SectionResult, LegibleV1Sections as LegibleSectionsHandle, V1DataElement, +}; +use pourover::{desc::ClassDesc, jni_method}; + +static LEGIBLE_V1_SECTIONS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/LegibleV1Sections"); + +/// Rust representation for `class LegibleV1Sections`. +#[repr(transparent)] +pub struct LegibleV1Sections<Obj>(pub Obj); + +impl<'local> LegibleV1Sections<JObject<'local>> { + /// Create new Java instance for the given handle. On the Java side this an `OwnedHandle` and + /// Java will be responsible to deallocating it. + pub fn construct( + env: &mut JNIEnv<'local>, + handle: LegibleSectionsHandle, + ) -> jni::errors::Result<Self> { + let handle_id = handle.get_as_handle().get_id() as jlong; + + pourover::call_constructor!(env, &LEGIBLE_V1_SECTIONS, "(J)V", handle_id,).map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> LegibleV1Sections<Obj> { + /// Get a reference to the inner `jni` crate [`JObject`]. + pub fn as_obj(&self) -> &JObject<'local> { + self.0.as_ref() + } + + /// Get the Rust [`HandleLike`] representation from this Java object. + pub fn as_rust_handle<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<LegibleSectionsHandle> { + let handle_id = self.get_handle_id(env)?; + Ok(LegibleSectionsHandle::from_handle(Handle::from_id(handle_id as u64))) + } + + /// Get `long handleId` from the Java object + fn get_handle_id<'env_local>( + &self, + env: &mut JNIEnv<'env_local>, + ) -> jni::errors::Result<jlong> { + use jni::signature::{Primitive, ReturnType}; + use pourover::desc::FieldDesc; + + static HANDLE_ID_FIELD: FieldDesc = LEGIBLE_V1_SECTIONS.field("handleId", "J"); + + env.get_field_unchecked( + self.0.as_ref(), + &HANDLE_ID_FIELD, + ReturnType::Primitive(Primitive::Long), + ) + .and_then(|val| val.j()) + } +} + +// Native method implementations + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "LegibleV1Sections")] +extern "system" fn nativeGetSection<'local>( + mut env: JNIEnv<'local>, + legible_sections_obj: LegibleV1Sections<JObject<'local>>, + index: jint, +) -> JObject<'local> { + let Ok(legible_sections) = legible_sections_obj.as_rust_handle(&mut env) else { + return JObject::null(); + }; + let Ok(index) = u8::try_from(index) else { + return JObject::null(); + }; + + let GetV1SectionResult::Success(section) = legible_sections.get_section(index) else { + return JObject::null(); + }; + + match DeserializedV1Section::construct( + &mut env, + legible_sections_obj, + index, + section.num_des(), + section.identity_kind(), + ) { + Ok(section) => section.0, + Err(_) => JObject::null(), + } +} + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "LegibleV1Sections")] +extern "system" fn nativeGetSectionDataElement<'local>( + mut env: JNIEnv<'local>, + legible_sections_obj: LegibleV1Sections<JObject<'local>>, + section_index: jint, + de_index: jint, +) -> JObject<'local> { + let Ok(legible_sections) = legible_sections_obj.as_rust_handle(&mut env) else { + return JObject::null(); + }; + let Ok(section_index) = u8::try_from(section_index) else { + return JObject::null(); + }; + let Ok(de_index) = u8::try_from(de_index) else { + return JObject::null(); + }; + + let GetV1DEResult::Success(de) = legible_sections.get_section_de(section_index, de_index) + else { + return JObject::null(); + }; + + let ret = match de { + V1DataElement::Generic(generic) => { + let de_type = jlong::from(generic.de_type().to_u32()); + let Some(slice) = generic.payload.as_slice() else { + return JObject::null(); + }; + + env.byte_array_from_slice(slice) + .and_then(|data| Generic::construct(&mut env, de_type, data)) + .map(|obj| obj.0) + } + }; + + ret.unwrap_or_else(|_err| JObject::null()) +} + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "LegibleV1Sections")] +extern "system" fn deallocate<'local>( + _env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, +) { + // Swallow errors here since there's nothing meaningful to do. + let _ = LegibleSectionsHandle::from_handle(Handle::from_id(handle_id as u64)).deallocate(); +}
diff --git a/nearby/presence/np_java_ffi/src/class/np_adv.rs b/nearby/presence/np_java_ffi/src/class/np_adv.rs new file mode 100644 index 0000000..88513cc --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/np_adv.rs
@@ -0,0 +1,95 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JByteArray, JClass, JObject}, + sys::{jint, jlong}, + JNIEnv, +}; + +use crate::class::{ + DeserializeResult, DeserializeResultError, DeserializedV0Advertisement, + DeserializedV1Advertisement, LegibleV1Sections, V0AdvertisementError, +}; +use handle_map::Handle; +use np_ffi_core::{credentials::CredentialBook, deserialize::deserialize_advertisement_from_slice}; +use pourover::{jni_method, ToUnsigned}; + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "NpAdv")] +extern "system" fn nativeDeserializeAdvertisement<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + service_data: JByteArray<'local>, + credential_book: jlong, +) -> JObject<'local> { + let credential_book = CredentialBook::from_handle(Handle::from_id(credential_book as u64)); + + // Unpack the service data + let mut service_data_buf = [0i8; 256]; + let Some(service_data) = env.get_array_length(&service_data).ok().and_then(|len| { + let len = usize::try_from(len).ok()?; + let region = service_data_buf.get_mut(0..len)?; + env.get_byte_array_region(&service_data, 0, region).ok()?; + Some(region.to_unsigned()) + }) else { + return DeserializeResult::construct_from_error( + &mut env, + DeserializeResultError::UnknownError, + ) + .map(|obj| obj.0) + .unwrap_or(JObject::null()); + }; + + use np_ffi_core::deserialize::{ + v0::DeserializedV0Advertisement::{Legible, NoMatchingCredentials}, + DeserializeAdvertisementResult::{Error, V0, V1}, + }; + + let res = match deserialize_advertisement_from_slice(service_data, credential_book) { + Error => { + DeserializeResult::construct_from_error(&mut env, DeserializeResultError::UnknownError) + .map(|obj| obj.0) + } + + V0(NoMatchingCredentials) => DeserializedV0Advertisement::construct_from_error( + &mut env, + V0AdvertisementError::NoMatchingCredentials, + ) + .and_then(|adv| DeserializeResult::from_v0_advertisement(&mut env, adv)) + .map(|obj| obj.0), + + V0(Legible(adv)) => DeserializedV0Advertisement::construct( + &mut env, + adv.num_des(), + adv.payload(), + adv.identity_kind(), + ) + .and_then(|adv| DeserializeResult::from_v0_advertisement(&mut env, adv)) + .map(|obj| obj.0), + + V1(adv) => LegibleV1Sections::construct(&mut env, adv.legible_sections) + .and_then(|sections| { + DeserializedV1Advertisement::construct( + &mut env, + jint::from(adv.num_legible_sections), + jint::from(adv.num_undecryptable_sections), + sections, + ) + }) + .and_then(|adv| DeserializeResult::from_v1_advertisement(&mut env, adv)) + .map(|res| res.0), + }; + + res.unwrap_or(JObject::null()) +}
diff --git a/nearby/presence/np_java_ffi/src/class/owned_handle.rs b/nearby/presence/np_java_ffi/src/class/owned_handle.rs new file mode 100644 index 0000000..8dc6e11 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/owned_handle.rs
@@ -0,0 +1,45 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JObject, JThrowable}, + JNIEnv, +}; +use pourover::desc::ClassDesc; + +static NO_SPACE_LEFT_EXCEPTION_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/OwnedHandle$NoSpaceLeftException"); + +/// Rust representation of `class OwnedHandle.NoSpaceLeftException`. +#[repr(transparent)] +pub struct NoSpaceLeftException<Obj>(pub Obj); + +impl<'local> NoSpaceLeftException<JObject<'local>> { + /// Create a new instance. + pub fn construct(env: &mut JNIEnv<'local>) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &NO_SPACE_LEFT_EXCEPTION_CLASS, "()V").map(Self) + } + + /// Create a new instance and throw it. + pub fn throw_new(env: &mut JNIEnv<'local>) -> jni::errors::Result<()> { + Self::construct(env)?.throw(env) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> NoSpaceLeftException<Obj> { + /// Throw this exception. + pub fn throw<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<()> { + env.throw(<&JThrowable>::from(self.0.as_ref())) + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/v0_data_element.rs b/nearby/presence/np_java_ffi/src/class/v0_data_element.rs new file mode 100644 index 0000000..759a486 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/v0_data_element.rs
@@ -0,0 +1,172 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Data Elementes for v0 advertisements. See `class V0DataElement`. + +use crate::class::IdentityKind; +use jni::{ + objects::{JClass, JObject}, + signature::{Primitive, ReturnType}, + sys::{jboolean, jint, JNI_FALSE, JNI_TRUE}, + JNIEnv, +}; +use np_ffi_core::{deserialize::v0::DeserializedV0IdentityKind, v0}; +use pourover::desc::{ClassDesc, FieldDesc}; + +static TX_POWER_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/V0DataElement$TxPower"); + +/// Rust representation of `class V0DataElement.TxPower`. +#[repr(transparent)] +pub struct TxPower<Obj>(pub Obj); + +impl<'local> TxPower<JObject<'local>> { + /// Create a new TxPower date element with the given `tx_power`. + pub fn construct(env: &mut JNIEnv<'local>, tx_power: jint) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &TX_POWER_CLASS, "(I)V", tx_power).map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> TxPower<Obj> { + /// Cast the given Java object to `TxPower` if it is an instance of the type. Returns `None` if + /// the object's type does not match. + pub fn checked_cast<'other_local>( + env: &mut JNIEnv<'other_local>, + obj: Obj, + ) -> jni::errors::Result<Option<Self>> { + Ok(env.is_instance_of(obj.as_ref(), &TX_POWER_CLASS)?.then(|| Self(obj))) + } + + /// Gets the value of the `int txPower` field. + pub fn get_tx_power<'env_local>( + &self, + env: &mut JNIEnv<'env_local>, + ) -> jni::errors::Result<jint> { + static TX_POWER_FIELD: FieldDesc = TX_POWER_CLASS.field("txPower", "I"); + env.get_field_unchecked( + self.0.as_ref(), + &TX_POWER_FIELD, + ReturnType::Primitive(Primitive::Int), + ) + .and_then(|ret| ret.i()) + } +} + +static V0_ACTIONS_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/V0DataElement$V0Actions"); + +/// Rust representation of `class V0DataElement.V0Actions`. +#[repr(transparent)] +pub struct V0Actions<Obj>(pub Obj); + +impl<'local> V0Actions<JObject<'local>> { + /// Create a new TxPower date element with the given identity and action bits. + pub fn construct( + env: &mut JNIEnv<'local>, + identity_kind: DeserializedV0IdentityKind, + action_bits: jint, + ) -> jni::errors::Result<Self> { + let identity_kind = IdentityKind::value_for_v0(env, identity_kind)?; + + pourover::call_constructor!(env, &V0_ACTIONS_CLASS, "(II)V", identity_kind, action_bits) + .map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> V0Actions<Obj> { + /// Cast the given Java object to `V0Actions` if it is an instance of the type. Returns `None` if + /// the object's type does not match. + pub fn checked_cast<'other_local>( + env: &mut JNIEnv<'other_local>, + obj: Obj, + ) -> jni::errors::Result<Option<Self>> { + Ok(env.is_instance_of(obj.as_ref(), &V0_ACTIONS_CLASS)?.then(|| Self(obj))) + } + + /// Get the `int identityKind` field from the Java object. + pub fn get_identity_kind<'env_local>( + &self, + env: &mut JNIEnv<'env_local>, + ) -> jni::errors::Result<jint> { + static IDENTITY_KIND: FieldDesc = V0_ACTIONS_CLASS.field("identityKind", "I"); + + env.get_field_unchecked( + self.0.as_ref(), + &IDENTITY_KIND, + ReturnType::Primitive(Primitive::Int), + ) + .and_then(|ret| ret.i()) + } + + /// Get the `int actionBits` field from the Java object. + pub fn get_action_bits<'env_local>( + &self, + env: &mut JNIEnv<'env_local>, + ) -> jni::errors::Result<jint> { + static ACTION_BITS_FIELD: FieldDesc = V0_ACTIONS_CLASS.field("actionBits", "I"); + + env.get_field_unchecked( + self.0.as_ref(), + &ACTION_BITS_FIELD, + ReturnType::Primitive(Primitive::Int), + ) + .and_then(|ret| ret.i()) + } +} + +/// Helper to build a [`V0Actions`][v0::V0Actions] instance from raw Java fields. +fn construct_actions_from_ints( + env: &mut JNIEnv<'_>, + identity_kind: jint, + action_bits: jint, +) -> Option<v0::V0Actions> { + let wrapper = if identity_kind == IdentityKind::plaintext(env).ok()? { + v0::V0Actions::Plaintext + } else if identity_kind == IdentityKind::decrypted(env).ok()? { + v0::V0Actions::Encrypted + } else { + return None; + }; + + let bits = v0::V0ActionBits::from(action_bits as u32); + + Some(wrapper(bits)) +} + +#[pourover::jni_method( + package = "com.google.android.nearby.presence.rust", + class = "V0DataElement.V0Actions" +)] +extern "system" fn nativeHasAction<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + identity_kind: jint, + action_bits: jint, + action: jint, +) -> jboolean { + let Some(actions) = construct_actions_from_ints(&mut env, identity_kind, action_bits) else { + return JNI_FALSE; + }; + + let Ok(action) = u8::try_from(action).map_err(From::from).and_then(v0::ActionType::try_from) + else { + return JNI_FALSE; + }; + + if actions.has_action(action).unwrap_or(false) { + JNI_TRUE + } else { + JNI_FALSE + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/v0_discovery_credential.rs b/nearby/presence/np_java_ffi/src/class/v0_discovery_credential.rs new file mode 100644 index 0000000..d8f21cf --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/v0_discovery_credential.rs
@@ -0,0 +1,72 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JByteArray, JObject}, + signature::ReturnType, + JNIEnv, +}; + +use np_ffi_core::credentials::V0DiscoveryCredential as CoreV0DiscoveryCredential; +use pourover::desc::{ClassDesc, FieldDesc}; + +static V0_DISCOVERY_CREDENTIAL_CLS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/credential/V0DiscoveryCredential"); + +/// Rust representation of `class V0DiscoveryCredential`. +#[repr(transparent)] +pub struct V0DiscoveryCredential<Obj>(pub Obj); + +impl<'local, Obj: AsRef<JObject<'local>>> V0DiscoveryCredential<Obj> { + /// Get an array field as a Rust array. + fn get_array<'env>( + &self, + env: &mut JNIEnv<'env>, + field: &FieldDesc, + ) -> jni::errors::Result<[u8; 32]> { + let arr: JByteArray<'env> = + env.get_field_unchecked(self.0.as_ref(), field, ReturnType::Array)?.l()?.into(); + + let mut buf = [0; 32]; + env.get_byte_array_region(arr, 0, &mut buf[..])?; + Ok(buf.map(|byte| byte as u8)) + } + + /// Get the key seed. + pub fn get_key_seed<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<[u8; 32]> { + static KEY_SEED: FieldDesc = V0_DISCOVERY_CREDENTIAL_CLS.field("keySeed", "[B"); + self.get_array(env, &KEY_SEED) + } + + /// Get the identity token hmac. + pub fn get_identity_token_hmac<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<[u8; 32]> { + static IDENTITY_TOKEN_HMAC: FieldDesc = + V0_DISCOVERY_CREDENTIAL_CLS.field("identityTokenHmac", "[B"); + self.get_array(env, &IDENTITY_TOKEN_HMAC) + } + + /// Convert this to the `np_ffi_core` representation. + pub fn get_as_core<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<CoreV0DiscoveryCredential> { + Ok(CoreV0DiscoveryCredential::new( + self.get_key_seed(env)?, + self.get_identity_token_hmac(env)?, + )) + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/v0_payload.rs b/nearby/presence/np_java_ffi/src/class/v0_payload.rs new file mode 100644 index 0000000..9b5e05b --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/v0_payload.rs
@@ -0,0 +1,73 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::class::v0_data_element::{TxPower, V0Actions}; +use handle_map::{Handle, HandleLike}; +use jni::{ + objects::{JClass, JObject}, + sys::{jint, jlong}, + JNIEnv, +}; +use np_ffi_core::deserialize::v0::{DeserializedV0IdentityKind, V0Payload}; +use np_ffi_core::v0::V0Actions as CoreV0Actions; +use pourover::jni_method; + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "V0Payload")] +extern "system" fn nativeGetDataElement<'local>( + mut env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, + index: jint, +) -> JObject<'local> { + let v0_payload = V0Payload::from_handle(Handle::from_id(handle_id as u64)); + let Ok(index) = u8::try_from(index) else { + return JObject::null(); + }; + + use np_ffi_core::{ + deserialize::v0::GetV0DEResult::{Error, Success}, + v0::V0DataElement::{Actions, TxPower as TxPow}, + }; + let ret = match v0_payload.get_de(index) { + Success(TxPow(tx_power)) => { + TxPower::construct(&mut env, jint::from(tx_power.as_i8())).map(|obj| obj.0) + } + Success(Actions(actions)) => { + let identity_kind = match &actions { + CoreV0Actions::Plaintext(_) => DeserializedV0IdentityKind::Plaintext, + CoreV0Actions::Encrypted(_) => DeserializedV0IdentityKind::Decrypted, + }; + + V0Actions::construct(&mut env, identity_kind, actions.as_u32() as jint).map(|obj| obj.0) + } + Error => { + return JObject::null(); + } + }; + + match ret { + Ok(de) => de, + Err(_jni_err) => JObject::null(), + } +} + +#[jni_method(package = "com.google.android.nearby.presence.rust", class = "V0Payload")] +extern "system" fn deallocate<'local>( + _env: JNIEnv<'local>, + _cls: JClass<'local>, + handle_id: jlong, +) { + // Swallow errors here since there's nothing meaningful to do. + let _ = V0Payload::from_handle(Handle::from_id(handle_id as u64)).deallocate(); +}
diff --git a/nearby/presence/np_java_ffi/src/class/v1_data_element.rs b/nearby/presence/np_java_ffi/src/class/v1_data_element.rs new file mode 100644 index 0000000..6401165 --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/v1_data_element.rs
@@ -0,0 +1,51 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Data Elements for v1 advertisements. See `class V1DataElement`. + +use jni::{ + objects::{JByteArray, JObject}, + sys::jlong, + JNIEnv, +}; +use pourover::desc::ClassDesc; + +static GENERIC_CLASS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/V1DataElement$Generic"); + +/// Rust representation of `class V1DataElement.Generic`. +#[repr(transparent)] +pub struct Generic<Obj>(pub Obj); + +impl<'local> Generic<JObject<'local>> { + /// Create a new Java instance from the given data element info. + pub fn construct<'data>( + env: &mut JNIEnv<'local>, + de_type: jlong, + data: JByteArray<'data>, + ) -> jni::errors::Result<Self> { + pourover::call_constructor!(env, &GENERIC_CLASS, "(J[B)V", de_type, data).map(Self) + } +} + +impl<'local, Obj: AsRef<JObject<'local>>> Generic<Obj> { + /// Cast the given Java object to `Generic` if it is an instance of the type. Returns `None` if + /// the object's type does not match. + pub fn checked_cast<'other_local>( + env: &mut JNIEnv<'other_local>, + obj: Obj, + ) -> jni::errors::Result<Option<Self>> { + Ok(env.is_instance_of(obj.as_ref(), &GENERIC_CLASS)?.then(|| Self(obj))) + } +}
diff --git a/nearby/presence/np_java_ffi/src/class/v1_discovery_credential.rs b/nearby/presence/np_java_ffi/src/class/v1_discovery_credential.rs new file mode 100644 index 0000000..923446a --- /dev/null +++ b/nearby/presence/np_java_ffi/src/class/v1_discovery_credential.rs
@@ -0,0 +1,101 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jni::{ + objects::{JByteArray, JObject}, + signature::ReturnType, + JNIEnv, +}; + +use np_ffi_core::credentials::V1DiscoveryCredential as CoreV1DiscoveryCredential; +use pourover::desc::{ClassDesc, FieldDesc}; + +static V1_DISCOVERY_CREDENTIAL_CLS: ClassDesc = + ClassDesc::new("com/google/android/nearby/presence/rust/credential/V1DiscoveryCredential"); + +/// Rust representation of `class V1DiscoveryCredential`. +#[repr(transparent)] +pub struct V1DiscoveryCredential<Obj>(pub Obj); + +impl<'local, Obj: AsRef<JObject<'local>>> V1DiscoveryCredential<Obj> { + /// Get an array field as a Rust array. + fn get_array<'env>( + &self, + env: &mut JNIEnv<'env>, + field: &FieldDesc, + ) -> jni::errors::Result<[u8; 32]> { + let arr: JByteArray<'env> = + env.get_field_unchecked(self.0.as_ref(), field, ReturnType::Array)?.l()?.into(); + + let mut buf = [0; 32]; + env.get_byte_array_region(arr, 0, &mut buf[..])?; + Ok(buf.map(|byte| byte as u8)) + } + + /// Get the key seed. + pub fn get_key_seed<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<[u8; 32]> { + static KEY_SEED: FieldDesc = V1_DISCOVERY_CREDENTIAL_CLS.field("keySeed", "[B"); + self.get_array(env, &KEY_SEED) + } + + /// Get the expected mic short salt identity token hmac. + pub fn get_expected_mic_short_salt_identity_token_hmac<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<[u8; 32]> { + static EXPECTED_MIC_SHORT_SALT_IDENTITY_TOKEN_HMAC: FieldDesc = + V1_DISCOVERY_CREDENTIAL_CLS.field("expectedMicShortSaltIdentityTokenHmac", "[B"); + self.get_array(env, &EXPECTED_MIC_SHORT_SALT_IDENTITY_TOKEN_HMAC) + } + + /// Get the expected mic extended salt identity token hmac. + pub fn get_expected_mic_extended_salt_identity_token_hmac<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<[u8; 32]> { + static EXPECTED_MIC_EXTENDED_SALT_IDENTITY_TOKEN_HMAC: FieldDesc = + V1_DISCOVERY_CREDENTIAL_CLS.field("expectedMicExtendedSaltIdentityTokenHmac", "[B"); + self.get_array(env, &EXPECTED_MIC_EXTENDED_SALT_IDENTITY_TOKEN_HMAC) + } + + /// Get the expected signature identity token hmac. + pub fn get_expected_signature_identity_token_hmac<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<[u8; 32]> { + static EXPECTED_SIGNATURE_IDENTITY_TOKEN_HMAC: FieldDesc = + V1_DISCOVERY_CREDENTIAL_CLS.field("expectedSignatureIdentityTokenHmac", "[B"); + self.get_array(env, &EXPECTED_SIGNATURE_IDENTITY_TOKEN_HMAC) + } + + /// Get the pub key. + pub fn get_pub_key<'env>(&self, env: &mut JNIEnv<'env>) -> jni::errors::Result<[u8; 32]> { + static PUB_KEY: FieldDesc = V1_DISCOVERY_CREDENTIAL_CLS.field("pubKey", "[B"); + self.get_array(env, &PUB_KEY) + } + + /// Convert this to the `np_ffi_core` representation. + pub fn get_as_core<'env>( + &self, + env: &mut JNIEnv<'env>, + ) -> jni::errors::Result<CoreV1DiscoveryCredential> { + Ok(CoreV1DiscoveryCredential::new( + self.get_key_seed(env)?, + self.get_expected_mic_short_salt_identity_token_hmac(env)?, + self.get_expected_mic_extended_salt_identity_token_hmac(env)?, + self.get_expected_signature_identity_token_hmac(env)?, + self.get_pub_key(env)?, + )) + } +}
diff --git a/nearby/util/pourover/src/lib.rs b/nearby/presence/np_java_ffi/src/lib.rs similarity index 71% copy from nearby/util/pourover/src/lib.rs copy to nearby/presence/np_java_ffi/src/lib.rs index 51495de..7a688e8 100644 --- a/nearby/util/pourover/src/lib.rs +++ b/nearby/presence/np_java_ffi/src/lib.rs
@@ -12,15 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Utilties for JNI interactions. +//! Java bindings for np_ffi_core. -// Enforce documentation -#![deny(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn)] +// Named lifetimes are being used to match jni crate conventions. +// See: https://docs.rs/jni/latest/jni/struct.JNIEnv.html#lifetime-names +#![allow(clippy::needless_lifetimes)] -pub use pourover_macro::jni_method; - -pub mod desc; - -mod conversions; -pub use conversions::{ToSigned, ToUnsigned}; +pub mod class;
diff --git a/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/DeserializeTests.java b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/DeserializeTests.java new file mode 100644 index 0000000..d4f146e --- /dev/null +++ b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/DeserializeTests.java
@@ -0,0 +1,199 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import static com.google.android.nearby.presence.rust.TestData.*; +import static com.google.android.nearby.presence.rust.credential.CredentialBook.NoMetadata; +import static com.google.common.truth.Truth.assertThat; + +import com.google.android.nearby.presence.rust.credential.CredentialBook; +import org.junit.jupiter.api.Test; + +public class DeserializeTests { + + DeserializeResult parsePublicAdv(byte[] bytes) { + // Call parse with an empty CredentialBook + try (CredentialBook<NoMetadata> book = CredentialBook.empty()) { + return NpAdv.deserializeAdvertisement(bytes, book); + } + } + + DeserializeResult parsePrivateAdv(byte[] bytes) { + try (CredentialBook<NoMetadata> book = + CredentialBook.<NoMetadata>builder() + .addDiscoveryCredential(V0_CRED, NoMetadata.INSTANCE) + .addDiscoveryCredential(V1_CRED, NoMetadata.INSTANCE) + .build()) { + return NpAdv.deserializeAdvertisement(bytes, book); + } + } + + @Test + void deserializeAdvertisement_v0_canParsePublic() { + try (DeserializeResult result = parsePublicAdv(V0_PUBLIC)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V0_ADVERTISEMENT); + + DeserializedV0Advertisement adv = result.getAsV0(); + + assertThat(adv).isNotNull(); + assertThat(adv.isLegible()).isTrue(); + assertThat(adv.getIdentity()).isEqualTo(IdentityKind.PLAINTEXT); + assertThat(adv.getDataElementCount()).isEqualTo(2); + } + } + + @Test + void deserializeAdvertisement_v0_canParsePublicWithCreds() { + try (DeserializeResult result = parsePrivateAdv(V0_PUBLIC)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V0_ADVERTISEMENT); + + DeserializedV0Advertisement adv = result.getAsV0(); + + assertThat(adv).isNotNull(); + assertThat(adv.isLegible()).isTrue(); + assertThat(adv.getIdentity()).isEqualTo(IdentityKind.PLAINTEXT); + assertThat(adv.getDataElementCount()).isEqualTo(2); + } + } + + @Test + void deserializeAdvertisement_v0_canParsePrivate() { + try (DeserializeResult result = parsePrivateAdv(V0_PRIVATE)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V0_ADVERTISEMENT); + + DeserializedV0Advertisement adv = result.getAsV0(); + + assertThat(adv).isNotNull(); + assertThat(adv.isLegible()).isTrue(); + assertThat(adv.getIdentity()).isEqualTo(IdentityKind.DECRYPTED); + assertThat(adv.getDataElementCount()).isEqualTo(1); + assertThat(adv.getDataElement(0)).isInstanceOf(V0DataElement.TxPower.class); + } + } + + @Test + void deserializeAdvertisement_v0_cannotParsePrivateWithoutCreds() { + try (DeserializeResult result = parsePublicAdv(V0_PRIVATE)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V0_ADVERTISEMENT); + + DeserializedV0Advertisement adv = result.getAsV0(); + + assertThat(adv).isNotNull(); + assertThat(adv.isLegible()).isFalse(); + } + } + + @Test + void deserializeAdvertisement_v0_canReadTxPowerDe() { + try (DeserializeResult result = parsePublicAdv(V0_PUBLIC)) { + DeserializedV0Advertisement adv = result.getAsV0(); + + V0DataElement de = adv.getDataElement(0); + + assertThat(de).isInstanceOf(V0DataElement.TxPower.class); + V0DataElement.TxPower txPower = (V0DataElement.TxPower) de; + assertThat(txPower.getTxPower()).isEqualTo(20); + } + } + + @Test + void deserializeAdvertisement_v0_canReadActionsDe() { + try (DeserializeResult result = parsePublicAdv(V0_PUBLIC)) { + DeserializedV0Advertisement adv = result.getAsV0(); + + V0DataElement de = adv.getDataElement(1); + + assertThat(de).isInstanceOf(V0DataElement.V0Actions.class); + V0DataElement.V0Actions actions = (V0DataElement.V0Actions) de; + assertThat(actions.getIdentityKind()).isEqualTo(IdentityKind.PLAINTEXT); + assertThat(actions.hasAction(V0DataElement.V0ActionType.NEARBY_SHARE)).isTrue(); + assertThat(actions.hasAction(V0DataElement.V0ActionType.CROSS_DEV_SDK)).isFalse(); + } + } + + @Test + void deserializeAdvertisement_v1_canParsePublic() { + try (DeserializeResult result = parsePublicAdv(V1_PUBLIC)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V1_ADVERTISEMENT); + + DeserializedV1Advertisement adv = result.getAsV1(); + + assertThat(adv).isNotNull(); + assertThat(adv.getNumLegibleSections()).isEqualTo(1); + assertThat(adv.getNumUndecryptableSections()).isEqualTo(0); + } + } + + @Test + void deserializeAdvertisement_v1_canParsePrivate() { + try (DeserializeResult result = parsePrivateAdv(V1_PRIVATE)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V1_ADVERTISEMENT); + + DeserializedV1Advertisement adv = result.getAsV1(); + + assertThat(adv).isNotNull(); + assertThat(adv.getNumLegibleSections()).isEqualTo(1); + assertThat(adv.getNumUndecryptableSections()).isEqualTo(0); + + DeserializedV1Section section = adv.getSection(0); + assertThat(section.getIdentityKind()).isEqualTo(IdentityKind.DECRYPTED); + assertThat(section.getDataElementCount()).isEqualTo(1); + } + } + + @Test + void deserializeAdvertisement_v1_canParsePrivateWithoutCreds() { + try (DeserializeResult result = parsePublicAdv(V1_PRIVATE)) { + assertThat(result.getKind()).isEqualTo(DeserializeResult.Kind.V1_ADVERTISEMENT); + + DeserializedV1Advertisement adv = result.getAsV1(); + + assertThat(adv).isNotNull(); + assertThat(adv.getNumLegibleSections()).isEqualTo(0); + assertThat(adv.getNumUndecryptableSections()).isEqualTo(1); + } + } + + @Test + void deserializeAdvertisement_v1_canParsePublicSection() { + try (DeserializeResult result = parsePublicAdv(V1_PUBLIC)) { + DeserializedV1Advertisement adv = result.getAsV1(); + + DeserializedV1Section section = adv.getSection(0); + + assertThat(section).isNotNull(); + assertThat(section.getIdentityKind()).isEqualTo(IdentityKind.PLAINTEXT); + assertThat(section.getDataElementCount()).isEqualTo(1); + } + } + + @Test + void deserializeAdvertisement_v1_canReadGenericDe() { + try (DeserializeResult result = parsePublicAdv(V1_PUBLIC)) { + DeserializedV1Advertisement adv = result.getAsV1(); + DeserializedV1Section section = adv.getSection(0); + + V1DataElement de = section.getDataElement(0); + + assertThat(de).isNotNull(); + assertThat(de).isInstanceOf(V1DataElement.Generic.class); + V1DataElement.Generic generic = (V1DataElement.Generic) de; + assertThat(generic.getType()).isEqualTo(0x05 /* V1 TxPower */); + assertThat(generic.getData()).asList().containsExactly((byte) 6); + } + } +}
diff --git a/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/TestData.java b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/TestData.java new file mode 100644 index 0000000..8ee26a1 --- /dev/null +++ b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/TestData.java
@@ -0,0 +1,410 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust; + +import com.google.android.nearby.presence.rust.credential.V0DiscoveryCredential; +import com.google.android.nearby.presence.rust.credential.V1DiscoveryCredential; + +public class TestData { + + public static final byte[] V0_PUBLIC = { + 0x00, // adv header + 0x15, 20, // tx power + 0x26, 0x00, 0x40, // actions + }; + + public static final byte[] V1_PUBLIC = { + 0x20, // NP Version Header + 0x00, // Section format + 0x02, // section len + 0x15, 0x06, // tx power value 6 + }; + + public static final byte[] V0_KEY_SEED = { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11 + }; + + public static final byte[] V0_IDENTITY_TOKEN = { + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33 + }; + + public static final byte[] V0_IDENTITY_TOKEN_HMAC = { + (byte) 0x09, + (byte) 0xFE, + (byte) 0x9E, + (byte) 0x81, + (byte) 0xB7, + (byte) 0x3E, + (byte) 0x5E, + (byte) 0xCC, + (byte) 0x76, + (byte) 0x59, + (byte) 0x57, + (byte) 0x71, + (byte) 0xE0, + (byte) 0x1F, + (byte) 0xFB, + (byte) 0x34, + (byte) 0x38, + (byte) 0xE7, + (byte) 0x5F, + (byte) 0x24, + (byte) 0xA7, + (byte) 0x69, + (byte) 0x56, + (byte) 0xA0, + (byte) 0xB8, + (byte) 0xEA, + (byte) 0x67, + (byte) 0xD1, + (byte) 0x1C, + (byte) 0x3E, + (byte) 0x36, + (byte) 0xFD + }; + + public static final V0DiscoveryCredential V0_CRED = + new V0DiscoveryCredential(V0_KEY_SEED, V0_IDENTITY_TOKEN_HMAC); + + public static final byte[] V0_PRIVATE = { + 0x04, // adv header + 0x22, + 0x22, // salt + (byte) 0xD8, + (byte) 0x22, + (byte) 0x12, + (byte) 0xEF, + (byte) 0x16, + (byte) 0xDB, + (byte) 0xF8, + (byte) 0x72, + (byte) 0xF2, + (byte) 0xA3, + (byte) 0xA7, + (byte) 0xC0, + (byte) 0xFA, + (byte) 0x52, + (byte) 0x48, + (byte) 0xEC // ciphertext for metadata key & txpower DE + }; + + public static final byte[] V1_IDENTITY_TOKEN = { + (byte) 0x58, + (byte) 0x31, + (byte) 0x00, + (byte) 0x48, + (byte) 0x11, + (byte) 0xe4, + (byte) 0xea, + (byte) 0x43, + (byte) 0xe9, + (byte) 0x01, + (byte) 0x76, + (byte) 0x25, + (byte) 0xd8, + (byte) 0xaf, + (byte) 0xd6, + (byte) 0x92 + }; + + public static final byte[] V1_KEY_SEED = { + (byte) 0xc8, + (byte) 0xdd, + (byte) 0x01, + (byte) 0x4d, + (byte) 0x25, + (byte) 0x01, + (byte) 0xc0, + (byte) 0xbf, + (byte) 0x5b, + (byte) 0x2a, + (byte) 0x05, + (byte) 0x48, + (byte) 0x49, + (byte) 0x8c, + (byte) 0xe6, + (byte) 0xbf, + (byte) 0x48, + (byte) 0x5b, + (byte) 0x89, + (byte) 0xb8, + (byte) 0x47, + (byte) 0x13, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xa0, + (byte) 0x18, + (byte) 0xac, + (byte) 0xd9, + (byte) 0xef, + (byte) 0x58, + (byte) 0x9f, + (byte) 0x76 + }; + + public static final byte[] V1_MIC_SHORT_HMAC = { + (byte) 0x09, + (byte) 0x48, + (byte) 0x4e, + (byte) 0x8f, + (byte) 0x39, + (byte) 0xdc, + (byte) 0x16, + (byte) 0x27, + (byte) 0x85, + (byte) 0x0a, + (byte) 0xea, + (byte) 0xfc, + (byte) 0x84, + (byte) 0xf6, + (byte) 0x43, + (byte) 0x51, + (byte) 0x62, + (byte) 0x16, + (byte) 0xf1, + (byte) 0x8d, + (byte) 0xda, + (byte) 0xd3, + (byte) 0xbc, + (byte) 0xba, + (byte) 0x43, + (byte) 0xf1, + (byte) 0x62, + (byte) 0x4e, + (byte) 0xa7, + (byte) 0x09, + (byte) 0xda, + (byte) 0xde + }; + + public static final byte[] V1_MIC_LONG_HMAC = { + (byte) 0xb9, + (byte) 0x6a, + (byte) 0xd2, + (byte) 0x3e, + (byte) 0x8e, + (byte) 0x08, + (byte) 0xe0, + (byte) 0xf4, + (byte) 0xe9, + (byte) 0xba, + (byte) 0xe9, + (byte) 0xbb, + (byte) 0x3d, + (byte) 0xe3, + (byte) 0x2f, + (byte) 0xd1, + (byte) 0x14, + (byte) 0x3a, + (byte) 0x51, + (byte) 0x19, + (byte) 0x54, + (byte) 0xf8, + (byte) 0x66, + (byte) 0x9f, + (byte) 0xf6, + (byte) 0xdb, + (byte) 0xf6, + (byte) 0x03, + (byte) 0xf7, + (byte) 0x41, + (byte) 0x20, + (byte) 0xd7 + }; + + public static final byte[] V1_SIG_HMAC = { + (byte) 0xc4, + (byte) 0x19, + (byte) 0x6e, + (byte) 0x84, + (byte) 0x95, + (byte) 0x3a, + (byte) 0x8a, + (byte) 0x97, + (byte) 0xb9, + (byte) 0xed, + (byte) 0xf0, + (byte) 0xba, + (byte) 0xd2, + (byte) 0x5d, + (byte) 0xa4, + (byte) 0x32, + (byte) 0xb1, + (byte) 0xf2, + (byte) 0x1a, + (byte) 0xf7, + (byte) 0x7d, + (byte) 0x95, + (byte) 0x8f, + (byte) 0xeb, + (byte) 0x5f, + (byte) 0xbe, + (byte) 0xfd, + (byte) 0x62, + (byte) 0xa7, + (byte) 0xc0, + (byte) 0x16, + (byte) 0x66 + }; + + public static final byte[] V1_PUB_KEY = { + (byte) 0x3c, + (byte) 0x59, + (byte) 0xd7, + (byte) 0x30, + (byte) 0x58, + (byte) 0x8c, + (byte) 0x45, + (byte) 0x26, + (byte) 0x7e, + (byte) 0x52, + (byte) 0x29, + (byte) 0x54, + (byte) 0xca, + (byte) 0xc9, + (byte) 0xcb, + (byte) 0xca, + (byte) 0x72, + (byte) 0x94, + (byte) 0x24, + (byte) 0xd8, + (byte) 0xf5, + (byte) 0xa6, + (byte) 0x1e, + (byte) 0xcf, + (byte) 0x04, + (byte) 0x3e, + (byte) 0x8f, + (byte) 0x91, + (byte) 0x81, + (byte) 0x6d, + (byte) 0x19, + (byte) 0x74 + }; + + public static final V1DiscoveryCredential V1_CRED = + new V1DiscoveryCredential( + V1_KEY_SEED, V1_MIC_SHORT_HMAC, V1_MIC_LONG_HMAC, V1_SIG_HMAC, V1_PUB_KEY); + + public static final byte[] V1_PRIVATE = { + (byte) 0x20, + (byte) 0x03, + (byte) 0xfc, + (byte) 0x32, + (byte) 0xb7, + (byte) 0x5d, + (byte) 0xdd, + (byte) 0x6a, + (byte) 0xdb, + (byte) 0xb0, + (byte) 0x89, + (byte) 0x7d, + (byte) 0xb9, + (byte) 0xcd, + (byte) 0xa9, + (byte) 0x6e, + (byte) 0x73, + (byte) 0x6d, + (byte) 0x7a, + (byte) 0xfc, + (byte) 0xeb, + (byte) 0x2b, + (byte) 0x0c, + (byte) 0x02, + (byte) 0x3d, + (byte) 0xc8, + (byte) 0xfa, + (byte) 0xc8, + (byte) 0x78, + (byte) 0x83, + (byte) 0x56, + (byte) 0xfa, + (byte) 0x53, + (byte) 0x11, + (byte) 0x42, + (byte) 0x08, + (byte) 0x9e, + (byte) 0xfe, + (byte) 0x70, + (byte) 0xd0, + (byte) 0x68, + (byte) 0x6c, + (byte) 0x7c, + (byte) 0x29, + (byte) 0x86, + (byte) 0xd6, + (byte) 0x76, + (byte) 0x2b, + (byte) 0x03, + (byte) 0xa4, + (byte) 0xc7, + (byte) 0x47, + (byte) 0x5c, + (byte) 0x41, + (byte) 0x9d, + (byte) 0x21, + (byte) 0x15, + (byte) 0x54, + (byte) 0x89, + (byte) 0x43, + (byte) 0x32, + (byte) 0x44, + (byte) 0x47, + (byte) 0x34, + (byte) 0xd7, + (byte) 0xbd, + (byte) 0x4f, + (byte) 0x38, + (byte) 0x83, + (byte) 0x74, + (byte) 0xe4, + (byte) 0xdb, + (byte) 0xcf, + (byte) 0xfe, + (byte) 0xe4, + (byte) 0x7a, + (byte) 0xae, + (byte) 0xa8, + (byte) 0xe2, + (byte) 0xf5, + (byte) 0x69, + (byte) 0xb8, + (byte) 0x42, + (byte) 0xf5, + (byte) 0x67, + (byte) 0x7a, + (byte) 0x34, + (byte) 0x6d, + (byte) 0x86, + (byte) 0x8b, + (byte) 0x4c, + (byte) 0xa9, + (byte) 0x7f, + (byte) 0x45, + (byte) 0x1c, + (byte) 0x37, + (byte) 0xf1, + (byte) 0x6e, + (byte) 0xfc, + (byte) 0xae, + (byte) 0xc6 + }; +}
diff --git a/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/credential/CredentialBookTests.java b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/credential/CredentialBookTests.java new file mode 100644 index 0000000..12302d3 --- /dev/null +++ b/nearby/presence/np_java_ffi/test/com/google/android/nearby/presence/rust/credential/CredentialBookTests.java
@@ -0,0 +1,40 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.nearby.presence.rust.credential; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.*; + +import java.lang.ref.Cleaner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class CredentialBookTests { + + @Mock Cleaner cleaner; + + @Test + void CredentialBook_wasRegisteredWithCleaner() { + try (CredentialBook book = new CredentialBook.Builder(cleaner).build()) { + assertThat(book).isNotNull(); + verify(cleaner).register(same(book), any()); + } + } +}
diff --git a/nearby/presence/rand_ext/src/lib.rs b/nearby/presence/rand_ext/src/lib.rs index d767143..587279d 100644 --- a/nearby/presence/rand_ext/src/lib.rs +++ b/nearby/presence/rand_ext/src/lib.rs
@@ -20,8 +20,8 @@ use alloc::vec::Vec; use crypto_provider::{CryptoProvider, CryptoRng}; use log::info; -pub use rand; use rand::{Rng as _, SeedableRng}; +pub use {rand, rand_pcg}; /// Returns a random Vec with the provided length. pub fn random_vec<C: CryptoProvider>(rng: &mut C::CryptoRng, len: usize) -> Vec<u8> { @@ -52,7 +52,7 @@ } /// Returns a fast rng seeded with the thread rng (which is itself seeded from the OS). -pub fn seeded_rng() -> impl rand::Rng { +pub fn seeded_rng() -> rand_pcg::Pcg64 { let mut seed: <rand_pcg::Pcg64 as rand::SeedableRng>::Seed = Default::default(); rand::thread_rng().fill(&mut seed); // print it out so if a test fails, the seed will be visible for further investigation
diff --git a/nearby/presence/test_helper/Cargo.toml b/nearby/presence/test_helper/Cargo.toml index c52d6bf..340a843 100644 --- a/nearby/presence/test_helper/Cargo.toml +++ b/nearby/presence/test_helper/Cargo.toml
@@ -10,3 +10,4 @@ [dependencies] hex.workspace = true serde_json.workspace = true +itertools.workspace = true
diff --git a/nearby/presence/test_helper/src/lib.rs b/nearby/presence/test_helper/src/lib.rs index 8b42623..76dccf4 100644 --- a/nearby/presence/test_helper/src/lib.rs +++ b/nearby/presence/test_helper/src/lib.rs
@@ -16,6 +16,7 @@ #![allow(clippy::unwrap_used, clippy::expect_used)] +use itertools::Itertools; use std::fs; use std::io::Read; @@ -62,3 +63,16 @@ pub fn string_to_hex(str: &str) -> Vec<u8> { hex::decode(str).unwrap() } + +/// Format data as hex bytes for the convenience of test data in FFI tests. +/// +/// # Examples +/// +/// ``` +/// use test_helper::hex_bytes; +/// +/// assert_eq!("0x12, 0x34", hex_bytes(&[0x12, 0x34])); +/// ``` +pub fn hex_bytes(data: impl AsRef<[u8]>) -> String { + hex::encode_upper(data).chars().tuples().map(|(a, b)| format!("0x{}{}", a, b)).join(", ") +}
diff --git a/nearby/presence/test_vector_hkdf/Cargo.toml b/nearby/presence/test_vector_hkdf/Cargo.toml new file mode 100644 index 0000000..cf5d1a2 --- /dev/null +++ b/nearby/presence/test_vector_hkdf/Cargo.toml
@@ -0,0 +1,17 @@ +[package] +name = "test_vector_hkdf" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[lints] +workspace = true + +[dependencies] +crypto_provider.workspace = true +crypto_provider_default = { workspace = true, features = ["rustcrypto"] } + +[dev-dependencies] + + +
diff --git a/nearby/presence/test_vector_hkdf/src/lib.rs b/nearby/presence/test_vector_hkdf/src/lib.rs new file mode 100644 index 0000000..d067eec --- /dev/null +++ b/nearby/presence/test_vector_hkdf/src/lib.rs
@@ -0,0 +1,91 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tools for generating test vector data in a repeatable way. +//! +//! The common approach of just using an RNG means that even a small change to how test vectors are +//! created will regenerate everything. Instead, by using a predictable seed and deriving data from +//! that with per-datum names, incremental changes can be made without regenerating everything. +//! +//! # Examples +//! +//! Generating 100 groups of data: +//! +//! ``` +//! use crypto_provider_default::CryptoProviderImpl; +//! use test_vector_hkdf::TestVectorHkdf; +//! +//! for i in 0_u32..100 { +//! let hkdf = TestVectorHkdf::<CryptoProviderImpl>::new( +//! "Spiffy test vectors - random seed: hunter2", +//! i.to_be_bytes().as_slice()); +//! +//! let vec = hkdf.derive_vec( +//! "fun data", +//! hkdf.derive_range_element("fun data length", 3..=18).try_into().unwrap()); +//! let array = hkdf.derive_array::<16>("array data"); +//! // store the generated data somewhere +//! } +//! ``` + +#![allow(clippy::unwrap_used)] + +use crypto_provider::hkdf::Hkdf; +use crypto_provider::CryptoProvider; +use crypto_provider_default::CryptoProviderImpl; +use std::ops; + +/// Typical usage would generate one instance per loop, and derive all data needed for that loop +/// iteration. +/// +/// The `description` passed to all `derive_` calls should be distinct, unless identical data is +/// desired. +pub struct TestVectorHkdf<C: CryptoProvider = CryptoProviderImpl> { + hkdf: C::HkdfSha256, +} + +impl<C: CryptoProvider> TestVectorHkdf<C> { + /// Create a new instance for the provided namespace and iteration. + /// + /// The namespace should contain a blob of randomly generated data. If reshuffling the generated + /// data is desired, just change the blob of random data. + pub fn new(namespace: &str, iteration: &[u8]) -> Self { + Self { hkdf: C::HkdfSha256::new(Some(namespace.as_bytes()), iteration) } + } + + /// Derive an array of `N` bytes. + pub fn derive_array<const N: usize>(&self, description: &str) -> [u8; N] { + let mut arr = [0; N]; + self.hkdf.expand(description.as_bytes(), &mut arr).unwrap(); + arr + } + + /// Derive a Vec of the specified `len`. + /// + /// # Panics + /// + /// Panics if `len` is too long for an HKDF output. + pub fn derive_vec(&self, description: &str, len: usize) -> Vec<u8> { + let mut vec = vec![0; len]; + self.hkdf.expand(description.as_bytes(), &mut vec).unwrap(); + vec + } + + /// Generated a biased element in a range using a sloppy sampling technique. + /// Will be increasingly biased as the range gets bigger. + pub fn derive_range_element(&self, description: &str, range: ops::RangeInclusive<u64>) -> u64 { + let num = u64::from_be_bytes(self.derive_array(description)); + num % (range.end() - range.start() + 1) + range.start() + } +}
diff --git a/nearby/presence/xts_aes/fuzz/Cargo.toml b/nearby/presence/xts_aes/fuzz/Cargo.toml index 4d00c49..5d99173 100644 --- a/nearby/presence/xts_aes/fuzz/Cargo.toml +++ b/nearby/presence/xts_aes/fuzz/Cargo.toml
@@ -9,27 +9,17 @@ cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4" -arbitrary = { version = "1.1.7", features = ["derive"] } +arbitrary = { workspace = true, features = ["derive"] } +crypto_provider.workspace = true +crypto_provider_rustcrypto.workspace = true +derive_fuzztest.workspace = true +ldt_tbc.workspace = true +xts_aes.workspace = true -[dependencies.xts_aes] -path = ".." - -[dependencies.crypto_provider] -path = "../../../crypto/crypto_provider" - -[dependencies.crypto_provider_rustcrypto] -path = "../../../crypto/crypto_provider_rustcrypto" - -[dependencies.ldt_tbc] -path = "../../../presence/ldt_tbc" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] +[target.'cfg(fuzzing)'.dependencies] +libfuzzer-sys.workspace = true [[bin]] -name = "xts-roundtrip" -path = "fuzz_targets/xts_roundtrip.rs" -test = false +name = "xts_roundtrip" +path = "src/bin/xts_roundtrip.rs" doc = false
diff --git a/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs b/nearby/presence/xts_aes/fuzz/src/bin/xts_roundtrip.rs similarity index 86% rename from nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs rename to nearby/presence/xts_aes/fuzz/src/bin/xts_roundtrip.rs index b7133de..f135c3b 100644 --- a/nearby/presence/xts_aes/fuzz/fuzz_targets/xts_roundtrip.rs +++ b/nearby/presence/xts_aes/fuzz/src/bin/xts_roundtrip.rs
@@ -1,4 +1,4 @@ -#![no_main] +#![cfg_attr(fuzzing, no_main)] // Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +14,12 @@ // limitations under the License. use crypto_provider_rustcrypto::RustCrypto; +use derive_fuzztest::fuzztest; use ldt_tbc::{TweakableBlockCipherDecrypter, TweakableBlockCipherEncrypter}; -use libfuzzer_sys::fuzz_target; use xts_aes::*; -fuzz_target!(|data: XtsFuzzInput| { +#[fuzztest] +fn test(data: XtsFuzzInput) { // XTS requires at least one block if data.plaintext.len() < 16 { return; @@ -37,14 +38,12 @@ let mut buffer = data.plaintext.clone(); - xts_enc - .encrypt_data_unit(tweak.clone(), &mut buffer[..]) - .unwrap(); + xts_enc.encrypt_data_unit(tweak.clone(), &mut buffer[..]).unwrap(); xts_dec.decrypt_data_unit(tweak, &mut buffer[..]).unwrap(); assert_eq!(data.plaintext, buffer); -}); +} -#[derive(Debug, arbitrary::Arbitrary)] +#[derive(Clone, Debug, arbitrary::Arbitrary)] struct XtsFuzzInput { key: [u8; 32], tweak: [u8; 16],
diff --git a/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs b/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs index abe1077..10b8c7d 100644 --- a/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs +++ b/nearby/presence/xts_aes/tests/compare_with_xts_mode_test.rs
@@ -15,16 +15,14 @@ #![allow(clippy::unwrap_used)] use aes::{cipher, cipher::KeyInit as _}; -use alloc::vec::Vec; use crypto_provider::aes::*; use crypto_provider::CryptoProvider; use crypto_provider_default::CryptoProviderImpl; use ldt_tbc::TweakableBlockCipherDecrypter; use ldt_tbc::TweakableBlockCipherEncrypter; -use rand::{self, distributions, Rng as _}; +use rand::{distributions, Rng as _}; use rand_ext::seeded_rng; use xts_aes::{Tweak, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; -extern crate alloc; #[test] fn identical_to_xtsmode_crate() {
diff --git a/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs b/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs index 1f92f89..ede231d 100644 --- a/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs +++ b/nearby/presence/xts_aes/tests/wycheproof_test_vectors.rs
@@ -20,7 +20,7 @@ use ldt_tbc::TweakableBlockCipherEncrypter; use ldt_tbc::TweakableBlockCipherKey; use wycheproof::cipher::TestGroup; -use xts_aes::{self, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; +use xts_aes::{XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; #[test] fn run_wycheproof_vectors() {
diff --git a/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs b/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs index 6ceb8b9..6661e96 100644 --- a/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs +++ b/nearby/presence/xts_aes/tests/xts_nist_test_vectors.rs
@@ -21,7 +21,7 @@ use ldt_tbc::TweakableBlockCipherEncrypter; use ldt_tbc::TweakableBlockCipherKey; use std::{collections::hash_map, fs, io, io::BufRead as _}; -use xts_aes::{self, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; +use xts_aes::{XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; #[test] fn nist_test_vectors_data_unit_seq_128() -> Result<(), anyhow::Error> {
diff --git a/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs index 924b665..ab967dc 100644 --- a/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs +++ b/nearby/presence/xts_aes/tests/xts_roundtrip_tests.rs
@@ -14,16 +14,14 @@ #![allow(clippy::unwrap_used)] -use alloc::vec::Vec; use crypto_provider::aes::*; use crypto_provider::CryptoProvider; use crypto_provider_default::CryptoProviderImpl; use ldt_tbc::TweakableBlockCipherDecrypter; use ldt_tbc::TweakableBlockCipherEncrypter; -use rand::{self, distributions, Rng as _}; +use rand::{distributions, Rng as _}; use rand_ext::seeded_rng; use xts_aes::{Tweak, XtsAes128Key, XtsAes256Key, XtsDecrypter, XtsEncrypter, XtsKey}; -extern crate alloc; #[test] fn roundtrip_self() {
diff --git a/nearby/util/pourover_macro_core/src/lib.rs b/nearby/src/coverage.rs similarity index 91% rename from nearby/util/pourover_macro_core/src/lib.rs rename to nearby/src/coverage.rs index ae06345..329e11c 100644 --- a/nearby/util/pourover_macro_core/src/lib.rs +++ b/nearby/src/coverage.rs
@@ -12,5 +12,3 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod jni_method; -pub use jni_method::jni_method;
diff --git a/nearby/src/crypto_ffi.rs b/nearby/src/crypto_ffi.rs index 42ac5ab..b1e08e9 100644 --- a/nearby/src/crypto_ffi.rs +++ b/nearby/src/crypto_ffi.rs
@@ -19,13 +19,8 @@ use crate::CargoOptions; -pub fn boringssl_check_everything(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()> { - check_boringssl(root, cargo_options)?; - Ok(()) -} - pub fn build_boringssl(root: &Path) -> anyhow::Result<()> { - let bindgen_version_req = VersionReq::parse(">=0.61.0")?; + let bindgen_version_req = VersionReq::parse(">=0.69.4")?; let bindgen_version = get_bindgen_version()?; if !bindgen_version_req.matches(&bindgen_version) { @@ -77,11 +72,42 @@ run_cmd_shell(&bssl_dir, format!("cargo check {locked_arg}"))?; run_cmd_shell(&bssl_dir, "cargo fmt --check")?; run_cmd_shell(&bssl_dir, "cargo clippy --all-targets")?; - run_cmd_shell(&bssl_dir, format!("cargo test {locked_arg} -- --color=always"))?; + run_cmd_shell(&bssl_dir, cargo_options.test("check_boringssl", ""))?; run_cmd_shell(&bssl_dir, "cargo doc --no-deps")?; + run_cmd_shell( + root, + cargo_options.test( + "check_boringssl_ukey2", + "-p ukey2_connections -p ukey2_rs --no-default-features --features test_boringssl", + ), + )?; + Ok(()) +} - run_cmd_shell(root, "cargo test -p ukey2_connections -p ukey2_rs --no-default-features --features test_boringssl")?; +/// Checks out latest boringssl commit and runs our crypto provider tests against it +pub fn check_boringssl_at_head(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()> { + // TODO: find a better way, a kokoro implemented auto-roller? + build_boringssl_at_latest(root)?; + let bssl_dir = root.join("crypto/crypto_provider_boringssl"); + run_cmd_shell(&bssl_dir, "cargo check")?; + run_cmd_shell(&bssl_dir, cargo_options.test("check_boringssl_latest", ""))?; + Ok(()) +} + +fn build_boringssl_at_latest(root: &Path) -> anyhow::Result<()> { + // Now check boringssl against HEAD. Kokoro does not allow us to directly update the git submodule + // so we must use manual hackery instead :/ + run_cmd_shell(root.parent().unwrap(), "rm -Rf third_party/boringssl")?; + run_cmd_shell( + &root.parent().unwrap().join("third_party"), + "git clone https://boringssl.googlesource.com/boringssl", + )?; + run_cmd_shell( + &root.parent().unwrap().join("third_party/boringssl"), + "git checkout origin/master", + )?; + build_boringssl(root)?; Ok(()) }
diff --git a/nearby/src/ffi.rs b/nearby/src/ffi.rs index 68e6e8c..ac0c585 100644 --- a/nearby/src/ffi.rs +++ b/nearby/src/ffi.rs
@@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::CargoOptions; +use crate::{crypto_ffi, CargoOptions}; use cmd_runner::{run_cmd_shell, run_cmd_shell_with_color, YellowStderr}; use std::{fs, path}; // wrapper for checking all ffi related things -pub fn check_everything(root: &path::Path, cargo_options: &CargoOptions) -> anyhow::Result<()> { +pub fn check_ffi(root: &path::Path, cargo_options: &CargoOptions) -> anyhow::Result<()> { + crypto_ffi::check_boringssl(root, cargo_options)?; check_np_ffi_cmake(root, cargo_options)?; check_ldt_cmake(root, cargo_options)?; @@ -33,7 +34,7 @@ run_cmd_shell_with_color::<YellowStderr>( &build_dir, - "cmake -G Ninja -DENABLE_TESTS=true -DCMAKE_BUILD_TYPE=Release ..", + "cmake -G Ninja -DENABLE_TESTS=true -DCMAKE_BUILD_TYPE=Release -DENABLE_FUZZ=false ..", )?; // verify sample and benchmarks build @@ -74,10 +75,10 @@ run_cmd_shell_with_color::<YellowStderr>( &build_dir, - "cmake -G Ninja -DENABLE_TESTS=true -DCMAKE_BUILD_TYPE=Release ..", + "cmake -G Ninja -DENABLE_TESTS=true -DCMAKE_BUILD_TYPE=Release -DENABLE_FUZZ=false ..", )?; - // verify sample and benchmarks build + run_cmd_shell(root, format!("cargo build {locked_arg} -p ldt_np_adv_ffi --quiet --release"))?; run_cmd_shell_with_color::<YellowStderr>(&build_dir, "cmake --build . --target ldt_c_sample")?; run_cmd_shell_with_color::<YellowStderr>( &build_dir,
diff --git a/nearby/src/fuzzers.rs b/nearby/src/fuzzers.rs index aba01b3..fa4f21e 100644 --- a/nearby/src/fuzzers.rs +++ b/nearby/src/fuzzers.rs
@@ -19,19 +19,19 @@ log::info!("Running rust fuzzers"); run_cmd_shell_with_color::<YellowStderr>( &root.join("presence/xts_aes"), - "cargo +nightly fuzz run xts-roundtrip -- -runs=10000 -max_total_time=60", + "cargo +nightly fuzz run xts_roundtrip -- -runs=10000 -max_total_time=60", )?; run_cmd_shell_with_color::<YellowStderr>( &root.join("presence/ldt"), - "cargo +nightly fuzz run ldt-roundtrip -- -runs=10000 -max_total_time=60", + "cargo +nightly fuzz run ldt_roundtrip -- -runs=10000 -max_total_time=60", )?; run_cmd_shell_with_color::<YellowStderr>( &root.join("presence/ldt_np_adv"), - "cargo +nightly fuzz run ldt-np-decrypt -- -runs=10000 -max_total_time=60", + "cargo +nightly fuzz run ldt_np_decrypt -- -runs=10000 -max_total_time=60", )?; run_cmd_shell_with_color::<YellowStderr>( &root.join("presence/ldt_np_adv"), - "cargo +nightly fuzz run ldt-np-roundtrip -- -runs=10000 -max_total_time=60", + "cargo +nightly fuzz run ldt_np_roundtrip -- -runs=10000 -max_total_time=60", )?; run_cmd_shell_with_color::<YellowStderr>( &root.join("connections/ukey2/ukey2_connections"), @@ -61,7 +61,7 @@ } // Runs the fuzztest fuzzers as short lived unit tests, compatible with gtest -pub(crate) fn build_fuzztest_uts(root: &path::Path) -> anyhow::Result<()> { +pub(crate) fn build_fuzztest_unit_tests(root: &path::Path) -> anyhow::Result<()> { log::info!("Checking fuzztest targets in unit test mode"); // first build the rust static libs to link against
diff --git a/nearby/src/jni.rs b/nearby/src/jni.rs index 0b000fb..54aafdc 100644 --- a/nearby/src/jni.rs +++ b/nearby/src/jni.rs
@@ -33,3 +33,10 @@ run_cmd_shell(&ukey2_jni_path, "./gradlew :test")?; Ok(()) } + +pub fn run_np_java_ffi_tests(root: &path::Path) -> anyhow::Result<()> { + run_cmd_shell(root, "cargo build -p np_java_ffi -F crypto_provider_default/rustcrypto")?; + let ukey2_jni_path = root.to_path_buf().join("presence/np_java_ffi"); + run_cmd_shell(&ukey2_jni_path, "./gradlew :test --info --rerun")?; + Ok(()) +}
diff --git a/nearby/src/license.rs b/nearby/src/license.rs index d9491b2..2229d04 100644 --- a/nearby/src/license.rs +++ b/nearby/src/license.rs
@@ -12,68 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use chrono::Datelike; -use file_header::{check_headers_recursively, license::spdx::*}; -use std::path; +use cmd_runner::license_checker::LicenseChecker; -pub(crate) fn check_license_headers(root: &path::Path) -> anyhow::Result<()> { - log::info!("Checking license headers"); - let ignore = license_ignore()?; - let results = check_headers_recursively( - root, - |p| !ignore.is_match(p), - APACHE_2_0.build_header(YearCopyrightOwnerValue::new( - u32::try_from(chrono::Utc::now().year())?, - "Google LLC".to_string(), - )), - 4, - )?; - - for path in results.no_header_files.iter() { - eprintln!("Header not present: {path:?}"); - } - - for path in results.binary_files.iter() { - eprintln!("Binary file: {path:?}"); - } - if !results.binary_files.is_empty() { - eprintln!("Consider adding binary files to the ignore list in src/licence.rs."); - } - - if results.has_failure() { - Err(anyhow::anyhow!("License header check failed")) - } else { - Ok(()) - } -} - -pub(crate) fn add_license_headers(root: &path::Path) -> anyhow::Result<()> { - let ignore = license_ignore()?; - for p in file_header::add_headers_recursively( - root, - |p| !ignore.is_match(p), - APACHE_2_0.build_header(YearCopyrightOwnerValue::new( - u32::try_from(chrono::Utc::now().year())?, - "Google LLC".to_string(), - )), - )? { - println!("Added header: {:?}", p); - } - - Ok(()) -} - -fn license_ignore() -> Result<globset::GlobSet, globset::Error> { - let mut builder = globset::GlobSetBuilder::new(); - for lic in license_ignore_dirs() { - builder.add(globset::Glob::new(lic)?); - } - builder.build() -} - -fn license_ignore_dirs() -> Vec<&'static str> { +pub const LICENSE_CHECKER: LicenseChecker = LicenseChecker { // These will be checked against the absolute path of each file. - vec![ + ignore: &[ "**/android/build/**", "**/target/**", "**/.idea/**", @@ -81,6 +24,7 @@ "**/java/build/**", "**/java/*/build/**", "**/ukey2_c_ffi/cpp/build/**", + "**/np_java_ffi/build/**", "**/*.toml", "**/*.md", "**/*.lock", @@ -110,15 +54,18 @@ "**/fuzz/artifacts/**", "**/cmake-build-debug/**", "**/tags", - ] -} + "**/MODULE.bazel", + "**/WORKSPACE", + "**/.bazelrc", + ], +}; #[cfg(test)] mod tests { + use super::LICENSE_CHECKER; + #[test] fn new_ignore_is_likely_buggy() { - for dir in super::license_ignore_dirs() { - assert!(dir.starts_with("**/"), "Matching on the root filesystem is likely unintended"); - } + LICENSE_CHECKER.check_new_ignore_is_likely_buggy() } }
diff --git a/nearby/src/main.rs b/nearby/src/main.rs index a38676f..25fe348 100644 --- a/nearby/src/main.rs +++ b/nearby/src/main.rs
@@ -15,8 +15,9 @@ extern crate core; use clap::Parser as _; -use cmd_runner::{run_cmd, run_cmd_shell, YellowStderr}; +use cmd_runner::{license_checker::LicenseSubcommand, run_cmd, run_cmd_shell, YellowStderr}; use env_logger::Env; +use license::LICENSE_CHECKER; use std::{env, ffi::OsString, path}; mod crypto_ffi; @@ -35,23 +36,33 @@ ); match cli.subcommand { - Subcommand::CheckEverything { ref check_options } => { - check_everything(&root_dir, check_options)? + Subcommand::RunDefaultChecks(ref check_options) => { + run_default_checks(&root_dir, check_options)?; + print!(concat!( + "Congratulations, the default checks passed. Since you like quality, here are\n", + "some more checks you may like:\n", + " cargo run -- run-rust-fuzzers\n", + " cargo run -- check-stack-usage\n", + )); } + Subcommand::VerifyCi { ref check_options } => verify_ci(&root_dir, check_options)?, Subcommand::CleanEverything => clean_everything(&root_dir)?, + Subcommand::CheckFormat(ref options) => check_format(&root_dir, options)?, Subcommand::CheckWorkspace(ref options) => check_workspace(&root_dir, options)?, - Subcommand::FfiCheckEverything(ref options) => ffi::check_everything(&root_dir, options)?, - Subcommand::BoringsslCheckEverything(ref options) => { - crypto_ffi::boringssl_check_everything(&root_dir, options)? - } + Subcommand::CheckAllFfi(ref options) => ffi::check_ffi(&root_dir, options)?, Subcommand::BuildBoringssl => crypto_ffi::build_boringssl(&root_dir)?, Subcommand::CheckBoringssl(ref options) => crypto_ffi::check_boringssl(&root_dir, options)?, + Subcommand::CheckBoringsslAtLatest(ref options) => { + crypto_ffi::check_boringssl_at_head(&root_dir, options)? + } Subcommand::RunRustFuzzers => fuzzers::run_rust_fuzzers(&root_dir)?, - Subcommand::CheckFuzztest => fuzzers::build_fuzztest_uts(&root_dir)?, - Subcommand::CheckLicenseHeaders => license::check_license_headers(&root_dir)?, - Subcommand::AddLicenseHeaders => license::add_license_headers(&root_dir)?, + Subcommand::CheckFuzztest => fuzzers::build_fuzztest_unit_tests(&root_dir)?, + Subcommand::License(license_subcommand) => { + license_subcommand.run(&LICENSE_CHECKER, &root_dir)? + } Subcommand::CheckUkey2Ffi(ref options) => ukey2::check_ukey2_ffi(&root_dir, options)?, Subcommand::RunUkey2JniTests => jni::run_ukey2_jni_tests(&root_dir)?, + Subcommand::RunNpJavaFfiTests => jni::run_np_java_ffi_tests(&root_dir)?, Subcommand::CheckLdtJni => jni::check_ldt_jni(&root_dir)?, Subcommand::CheckLdtCmake(ref options) => ffi::check_ldt_cmake(&root_dir, options)?, Subcommand::CheckNpFfiCmake(ref options) => ffi::check_np_ffi_cmake(&root_dir, options)?, @@ -61,7 +72,7 @@ Ok(()) } -fn check_format(root: &path::Path, options: &CheckOptions) -> anyhow::Result<()> { +fn check_format(root: &path::Path, options: &FormatterOptions) -> anyhow::Result<()> { // Rust format { let fmt_command = if options.reformat { "cargo fmt" } else { "cargo fmt --check" }; @@ -112,15 +123,18 @@ log::info!("Running cargo checks on workspace"); // ensure formatting is correct (Check for it first because it is fast compared to running tests) - check_format(root, options)?; + check_format(root, &options.formatter_options)?; for cargo_cmd in [ // make sure everything compiles "cargo check --workspace --all-targets --quiet", // run all the tests - "cargo test --workspace --quiet -- --color=always", + &options.cargo_options.test("check_workspace", "--workspace --quiet"), // Test ukey2 builds with different crypto providers - "cargo test -p ukey2_connections -p ukey2_rs --no-default-features --features test_rustcrypto", + &options.cargo_options.test( + "check_workspace_ukey2", + "-p ukey2_connections -p ukey2_rs --no-default-features --features test_rustcrypto", + ), // ensure the docs are valid (cross-references to other code, etc) concat!( "RUSTDOCFLAGS='--deny warnings' ", @@ -136,19 +150,28 @@ Ok(()) } -/// Runs checks to ensure lints are passing and all targets are building -pub fn check_everything(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> { - license::check_license_headers(root)?; +/// Runs default checks that are suiable for verifying a local change. +pub fn run_default_checks(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> { + license::LICENSE_CHECKER.check(root)?; check_workspace(root, check_options)?; crypto_ffi::check_boringssl(root, &check_options.cargo_options)?; - ffi::check_everything(root, &check_options.cargo_options)?; - jni::check_ldt_jni(root)?; - jni::run_kotlin_tests(root)?; - jni::run_ukey2_jni_tests(root)?; + ffi::check_ffi(root, &check_options.cargo_options)?; + if !cfg!(target_os = "windows") { + fuzzers::build_fuzztest_unit_tests(root)?; + } + crypto_ffi::check_boringssl_at_head(root, &check_options.cargo_options)?; ukey2::check_ukey2_ffi(root, &check_options.cargo_options)?; - fuzzers::run_rust_fuzzers(root)?; - fuzzers::build_fuzztest_uts(root)?; + if !cfg!(target_os = "windows") { + // Test below requires Java SE 9, but on Windows we only have Java SE 8 installed + jni::run_np_java_ffi_tests(root)?; + } + jni::run_ukey2_jni_tests(root)?; + Ok(()) +} +/// Runs checks to ensure lints are passing and all targets are building +pub fn verify_ci(root: &path::Path, check_options: &CheckOptions) -> anyhow::Result<()> { + run_default_checks(root, check_options)?; Ok(()) } @@ -157,6 +180,7 @@ run_cmd_shell(&root.join("presence/np_c_ffi"), "cargo clean")?; run_cmd_shell(&root.join("crypto/crypto_provider_boringssl"), "cargo clean")?; run_cmd_shell(&root.join("connections/ukey2/ukey2_c_ffi"), "cargo clean")?; + run_cmd_shell(&root.join("presence/np_java_ffi"), "./gradlew :clean")?; Ok(()) } @@ -168,37 +192,39 @@ #[derive(clap::Subcommand, Debug, Clone)] enum Subcommand { - /// Checks everything in beto-rust - CheckEverything { + /// Runs all of the checks that CI runs + VerifyCi { #[command(flatten)] check_options: CheckOptions, }, + /// Runs the default set of checks suitable for verifying local changes. + RunDefaultChecks(CheckOptions), /// Cleans the main workspace and all sub projects - useful if upgrading rust compiler version /// and need dependencies to be compiled with the same version CleanEverything, + /// Checks code formatting + CheckFormat(FormatterOptions), /// Checks everything included in the top level workspace CheckWorkspace(CheckOptions), - /// Checks everything related to the boringssl version - BoringsslCheckEverything(CargoOptions), /// Clones boringssl and uses bindgen to generate the rust crate BuildBoringssl, /// Run crypto provider tests using boringssl backend CheckBoringssl(CargoOptions), + /// Checks out latest boringssl commit and runs our tests against it + CheckBoringsslAtLatest(CargoOptions), /// Build and run pure Rust fuzzers for 10000 runs RunRustFuzzers, /// Builds and runs fuzztest property based unit tests CheckFuzztest, /// Builds and runs tests for all C/C++ projects. This is a combination of CheckNpFfi, /// CheckLdtFfi, and CheckCmakeBuildAndTests - FfiCheckEverything(CargoOptions), + CheckAllFfi(CargoOptions), /// Checks the CMake build and runs all of the C/C++ tests CheckLdtCmake(CargoOptions), /// Checks the CMake build and runs all of the C/C++ tests CheckNpFfiCmake(CargoOptions), - /// Checks the workspace 3rd party crates and makes sure they have a valid license - CheckLicenseHeaders, - /// Generate new headers for any files that are missing them - AddLicenseHeaders, + #[command(flatten)] + License(LicenseSubcommand), /// Builds and runs tests for the UKEY2 FFI CheckUkey2Ffi(CargoOptions), /// Checks the build of ldt_jni wrapper with non default features, ie boringssl @@ -207,12 +233,20 @@ RunKotlinTests, /// Checks the build of the ukey2_jni wrapper and runs tests RunUkey2JniTests, + /// Checks the build of the np_java_ffi wrapper and runs tests + RunNpJavaFfiTests, +} + +#[derive(clap::Args, Debug, Clone, Default)] +pub struct FormatterOptions { + #[arg(long, help = "reformat files files in the workspace with the code formatter")] + reformat: bool, } #[derive(clap::Args, Debug, Clone, Default)] pub struct CheckOptions { - #[arg(long, help = "reformat files with cargo fmt")] - reformat: bool, + #[command(flatten)] + formatter_options: FormatterOptions, #[command(flatten)] cargo_options: CargoOptions, } @@ -221,4 +255,23 @@ pub struct CargoOptions { #[arg(long, help = "whether to run cargo with --locked")] locked: bool, + #[arg(long, help = "gather coverage metrics")] + coverage: bool, +} + +impl CargoOptions { + /// Run `cargo test` or `cargo llvm-cov` depending on the configured options. + pub fn test(&self, tag: &str, args: impl AsRef<str>) -> String { + format!( + "cargo {subcommand} {locked} {args} {cov_args} -- --color=always", + subcommand = if self.coverage { "llvm-cov" } else { "test" }, + locked = if self.locked { "--locked" } else { "" }, + args = args.as_ref(), + cov_args = if self.coverage { + format!("--lcov --output-path \"target/{tag}.info\"") + } else { + String::default() + }, + ) + } }
diff --git a/nearby/util/pourover_macro/Cargo.toml b/nearby/util/pourover_macro/Cargo.toml deleted file mode 100644 index ac230b1..0000000 --- a/nearby/util/pourover_macro/Cargo.toml +++ /dev/null
@@ -1,11 +0,0 @@ -[package] -name = "pourover_macro" -version.workspace = true -edition.workspace = true -publish.workspace = true - -[lib] -proc-macro = true - -[dependencies] -pourover_macro_core.workspace = true
diff --git a/nearby/util/pourover_macro/src/lib.rs b/nearby/util/pourover_macro/src/lib.rs deleted file mode 100644 index 9f62354..0000000 --- a/nearby/util/pourover_macro/src/lib.rs +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -extern crate proc_macro; - -use pourover_macro_core as core; -use proc_macro::TokenStream; - -/// Export a function as a JNI native method. This will attach a `#[export_name = "..."]` attribute that -/// is formatted with the given parameters. -/// -/// # Parameters -/// - `package` (lit str): the Java package for the class being implemented -/// - `class` (lit str): the Java class being implemented. Use `Foo.Inner` syntax for inner -/// classes. -/// - `panic_returns` (expr): the value to return when a panic is encountered. This can not access -/// local variables. This may only be used with `panic=unwind` and will produce a compile error -/// otherwise. -/// -/// When using `panic_returns` function arguments must be [`std::panic::UnwindSafe`]. See -/// [`std::panic::catch_unwind`] for details. In practice this will not cause issues as JNI -/// arguments and return values are passed by pointer or value and not by Rust reference. -/// -/// # Example -/// ``` -/// # use pourover_macro::jni_method; -/// # #[allow(non_camel_case_types)] type jint = i32; // avoid jni dep for test -/// # type JNIEnv<'local> = *mut (); -/// # type JObject<'local> = *mut (); -/// -/// #[jni_method(package = "my.package", class = "Foo", panic_returns = -1)] -/// extern "system" fn getFoo<'local>( -/// mut env: JNIEnv<'local>, -/// this: JObject<'local>, -/// ) -> jint { -/// // ... -/// 0 -/// } -/// ``` -/// -/// This function will be exported with `#[export_name = "Java_my_package_Foo_getFoo"]`. -#[proc_macro_attribute] -pub fn jni_method(meta: TokenStream, item: TokenStream) -> TokenStream { - core::jni_method(meta.into(), item.into()).into() -}
diff --git a/nearby/util/pourover_macro_core/Cargo.toml b/nearby/util/pourover_macro_core/Cargo.toml deleted file mode 100644 index 04882d1..0000000 --- a/nearby/util/pourover_macro_core/Cargo.toml +++ /dev/null
@@ -1,10 +0,0 @@ -[package] -name = "pourover_macro_core" -version.workspace = true -edition.workspace = true -publish.workspace = true - -[dependencies] -proc-macro2.workspace = true -syn.workspace = true -quote.workspace = true
diff --git a/remoteauth/Cargo.lock b/remoteauth/Cargo.lock index 55841b9..1123c44 100644 --- a/remoteauth/Cargo.lock +++ b/remoteauth/Cargo.lock
@@ -4,18 +4,33 @@ [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] -name = "anstream" -version = "0.5.0" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -46,17 +61,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -66,23 +81,45 @@ checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "build-scripts" version = "0.1.0" dependencies = [ "anyhow", "clap", - "cmd-runner", + "cmd_runner", "env_logger", "log", ] [[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -92,21 +129,40 @@ ] [[package]] -name = "clap" -version = "4.4.1" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.4", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -116,9 +172,9 @@ [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", "proc-macro2", @@ -128,17 +184,23 @@ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] -name = "cmd-runner" +name = "cmd_runner" version = "0.1.0" dependencies = [ "anyhow", + "chrono", + "clap", + "file-header", + "globset", + "log", "owo-colors", "shell-escape", + "xshell", ] [[package]] @@ -148,6 +210,68 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] name = "ctap_protocol" version = "0.1.0" dependencies = [ @@ -175,7 +299,7 @@ dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -189,10 +313,36 @@ ] [[package]] -name = "heck" -version = "0.4.1" +name = "file-header" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "b5568149106e77ae33bc3a2c3ef3839cbe63ffa4a8dd4a81612a6f9dfdbc2e9f" +dependencies = [ + "crossbeam", + "lazy_static", + "license", + "thiserror", + "walkdir", +] + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -207,6 +357,29 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] name = "is-terminal" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -214,16 +387,48 @@ dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] +name = "license" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778718185117620a06e95d2b1e57d50166b1d6bfad93c8abfc1b3344c863ad8c" +dependencies = [ + "reword", + "serde", + "serde_json", +] + +[[package]] name = "linux-raw-sys" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -231,21 +436,30 @@ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "owo-colors" @@ -262,18 +476,18 @@ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -286,8 +500,8 @@ dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", ] [[package]] @@ -298,7 +512,18 @@ dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.5", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", ] [[package]] @@ -308,6 +533,12 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] name = "remote_auth_protocol" version = "0.1.0" dependencies = [ @@ -315,6 +546,15 @@ ] [[package]] +name = "reword" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe272098dce9ed76b479995953f748d1851261390b08f8a0ff619c885a1f0765" +dependencies = [ + "unicode-segmentation", +] + +[[package]] name = "rustix" version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -324,7 +564,53 @@ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", ] [[package]] @@ -335,15 +621,15 @@ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.28" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -360,18 +646,108 @@ ] [[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -403,12 +779,30 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -417,13 +811,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -433,37 +842,94 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "xshell" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" +dependencies = [ + "xshell-macros", +] + +[[package]] +name = "xshell-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
diff --git a/remoteauth/Cargo.toml b/remoteauth/Cargo.toml index 20b2ec3..d86adc0 100644 --- a/remoteauth/Cargo.toml +++ b/remoteauth/Cargo.toml
@@ -22,6 +22,6 @@ [dependencies] anyhow.workspace = true clap = { version = "4.0.25", features = ["derive"] } -cmd-runner = { path = "../cmd-runner" } +cmd_runner = { path = "../common/cmd_runner" } env_logger = "0.10.0" log = "0.4.17" \ No newline at end of file