aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinlin <cinlin@google.com>2023-07-11 14:52:51 -0700
committerCopybara-Service <copybara-worker@google.com>2023-07-11 14:56:04 -0700
commit10c008a4d077fadcd78ba02665b1088da98b3351 (patch)
tree45d62d596cce8323c096b701c7d4d28961781702
parenta14cdf3e36d2207b4849e28fff402f40cb69549a (diff)
downloadtink-10c008a4d077fadcd78ba02665b1088da98b3351.tar.gz
Add deterministic AEAD to C++ examples directory.
Keyset generated via ```tinkey create-keyset --key-template AES256_SIV --out keyset.json``` PiperOrigin-RevId: 547304870
-rw-r--r--cc/examples/daead/BUILD.bazel40
-rw-r--r--cc/examples/daead/CMakeLists.txt16
-rw-r--r--cc/examples/daead/deterministic_aead_cli.cc134
-rwxr-xr-xcc/examples/daead/deterministic_aead_cli_test.sh215
-rw-r--r--cc/examples/daead/deterministic_aead_test_keyset.json15
5 files changed, 420 insertions, 0 deletions
diff --git a/cc/examples/daead/BUILD.bazel b/cc/examples/daead/BUILD.bazel
new file mode 100644
index 000000000..2e2637bf3
--- /dev/null
+++ b/cc/examples/daead/BUILD.bazel
@@ -0,0 +1,40 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+filegroup(
+ name = "deterministic_aead_test_keyset",
+ srcs = ["deterministic_aead_test_keyset.json"],
+)
+
+cc_binary(
+ name = "deterministic_aead_cli",
+ srcs = ["deterministic_aead_cli.cc"],
+ deps = [
+ "//util",
+ "@com_google_absl//absl/flags:flag",
+ "@com_google_absl//absl/flags:parse",
+ "@com_google_absl//absl/log:check",
+ "@com_google_absl//absl/strings",
+ "@tink_cc//:deterministic_aead",
+ "@tink_cc//:keyset_handle",
+ "@tink_cc//:keyset_reader",
+ "@tink_cc//config:tink_config",
+ "@tink_cc//daead:deterministic_aead_config",
+ "@tink_cc//util:status",
+ ],
+)
+
+sh_test(
+ name = "deterministic_aead_cli_test",
+ size = "small",
+ srcs = ["deterministic_aead_cli_test.sh"],
+ args = [
+ "$(rootpath :deterministic_aead_cli)",
+ "$(rootpath :deterministic_aead_test_keyset)",
+ ],
+ data = [
+ ":deterministic_aead_cli",
+ ":deterministic_aead_test_keyset",
+ ],
+)
diff --git a/cc/examples/daead/CMakeLists.txt b/cc/examples/daead/CMakeLists.txt
new file mode 100644
index 000000000..bd4b9e1e9
--- /dev/null
+++ b/cc/examples/daead/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_executable(deterministic_aead_cli deterministic_aead_cli.cc)
+target_include_directories(deterministic_aead_cli PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${TINK_EXAMPLES_INCLUDE_PATH}")
+target_link_libraries(deterministic_aead_cli
+ tink::static
+ absl::check
+ absl::flags_parse
+ util)
+
+add_test(
+ NAME deterministic_aead_cli_test
+ COMMAND "${BASH_PROGRAM}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/deterministic_aead_cli_test.sh"
+ "${CMAKE_CURRENT_BINARY_DIR}/deterministic_aead_cli"
+ "${CMAKE_CURRENT_SOURCE_DIR}/deterministic_aead_test_keyset.json")
diff --git a/cc/examples/daead/deterministic_aead_cli.cc b/cc/examples/daead/deterministic_aead_cli.cc
new file mode 100644
index 000000000..fc2d29854
--- /dev/null
+++ b/cc/examples/daead/deterministic_aead_cli.cc
@@ -0,0 +1,134 @@
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+// [START daead-example]
+// A command-line utility for testing Tink Deterministic AEAD.
+#include <iostream>
+#include <memory>
+#include <ostream>
+#include <string>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "absl/log/check.h"
+#include "absl/strings/string_view.h"
+#include "tink/daead/deterministic_aead_config.h"
+#include "tink/deterministic_aead.h"
+#include "util/util.h"
+#include "tink/keyset_handle.h"
+#include "tink/util/status.h"
+
+ABSL_FLAG(std::string, keyset_filename, "", "Keyset file in JSON format");
+ABSL_FLAG(std::string, mode, "", "Mode of operation {encrypt|decrypt}");
+ABSL_FLAG(std::string, input_filename, "", "Filename to operate on");
+ABSL_FLAG(std::string, output_filename, "", "Output file name");
+ABSL_FLAG(std::string, associated_data, "",
+ "Associated data for Deterministic AEAD (default: empty");
+
+namespace {
+
+using ::crypto::tink::DeterministicAead;
+using ::crypto::tink::DeterministicAeadConfig;
+using ::crypto::tink::KeysetHandle;
+using ::crypto::tink::util::Status;
+using ::crypto::tink::util::StatusOr;
+
+constexpr absl::string_view kEncrypt = "encrypt";
+constexpr absl::string_view kDecrypt = "decrypt";
+
+void ValidateParams() {
+ // [START_EXCLUDE]
+ CHECK(absl::GetFlag(FLAGS_mode) == kEncrypt ||
+ absl::GetFlag(FLAGS_mode) == kDecrypt)
+ << "Invalid mode; must be `encrypt` or `decrypt`";
+ CHECK(!absl::GetFlag(FLAGS_keyset_filename).empty())
+ << "Keyset file must be specified";
+ CHECK(!absl::GetFlag(FLAGS_input_filename).empty())
+ << "Input file must be specified";
+ CHECK(!absl::GetFlag(FLAGS_output_filename).empty())
+ << "Output file must be specified";
+ // [END_EXCLUDE]
+}
+
+} // namespace
+
+namespace tink_cc_examples {
+
+// Deterministic AEAD example CLI implementation.
+Status DeterministicAeadCli(absl::string_view mode,
+ const std::string& keyset_filename,
+ const std::string& input_filename,
+ const std::string& output_filename,
+ absl::string_view associated_data) {
+ Status result = DeterministicAeadConfig::Register();
+ if (!result.ok()) return result;
+
+ // Read keyset from file.
+ StatusOr<std::unique_ptr<KeysetHandle>> keyset_handle =
+ ReadJsonCleartextKeyset(keyset_filename);
+ if (!keyset_handle.ok()) return keyset_handle.status();
+
+ // Get the primitive.
+ StatusOr<std::unique_ptr<DeterministicAead>> daead =
+ (*keyset_handle)->GetPrimitive<DeterministicAead>();
+ if (!daead.ok()) return daead.status();
+
+ // Read the input.
+ StatusOr<std::string> input_file_content = ReadFile(input_filename);
+ if (!input_file_content.ok()) return input_file_content.status();
+
+ // Compute the output.
+ std::string output;
+ if (mode == kEncrypt) {
+ StatusOr<std::string> result = (*daead)->EncryptDeterministically(
+ *input_file_content, associated_data);
+ if (!result.ok()) return result.status();
+ output = *result;
+ } else if (mode == kDecrypt) {
+ StatusOr<std::string> result = (*daead)->DecryptDeterministically(
+ *input_file_content, associated_data);
+ if (!result.ok()) return result.status();
+ output = *result;
+ }
+
+ // Write output to file.
+ return WriteToFile(output, output_filename);
+}
+
+} // namespace tink_cc_examples
+
+int main(int argc, char** argv) {
+ absl::ParseCommandLine(argc, argv);
+
+ ValidateParams();
+
+ std::string mode = absl::GetFlag(FLAGS_mode);
+ std::string keyset_filename = absl::GetFlag(FLAGS_keyset_filename);
+ std::string input_filename = absl::GetFlag(FLAGS_input_filename);
+ std::string output_filename = absl::GetFlag(FLAGS_output_filename);
+ std::string associated_data = absl::GetFlag(FLAGS_associated_data);
+
+ std::clog << "Using keyset from file " << keyset_filename
+ << " to Deterministic AEAD-" << mode << " file " << input_filename
+ << " with associated data '" << associated_data << "'."
+ << std::endl;
+ std::clog << "The resulting output will be written to " << output_filename
+ << "." << std::endl;
+
+ CHECK_OK(tink_cc_examples::DeterministicAeadCli(
+ mode, keyset_filename, input_filename, output_filename, associated_data));
+ return 0;
+}
+// [END daead-example]
diff --git a/cc/examples/daead/deterministic_aead_cli_test.sh b/cc/examples/daead/deterministic_aead_cli_test.sh
new file mode 100755
index 000000000..553e7a188
--- /dev/null
+++ b/cc/examples/daead/deterministic_aead_cli_test.sh
@@ -0,0 +1,215 @@
+#!/bin/bash
+# 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.
+################################################################################
+
+set -euo pipefail
+
+#############################################################################
+# Tests for Tink CC Deterministic AEAD.
+#############################################################################
+
+: "${TEST_TMPDIR:=$(mktemp -d)}"
+
+readonly CLI="$1"
+readonly KEYSET_FILE="$2"
+readonly DATA_FILE="${TEST_TMPDIR}/example_data.txt"
+readonly TEST_NAME="TinkExamplesCcDeterministicAeadTest"
+
+echo "This is some plaintext to be encrypted." > "${DATA_FILE}"
+
+#######################################
+# A helper function for getting the return code of a command that may fail.
+# Temporarily disables error safety and stores return value in TEST_STATUS.
+#
+# Globals:
+# TEST_STATUS
+# Arguments:
+# Command to execute.
+#######################################
+test_command() {
+ set +e
+ "$@"
+ TEST_STATUS=$?
+ set -e
+}
+
+#######################################
+# Asserts that the outcome of the latest test command is 0.
+#
+# If not, it terminates the test execution.
+#
+# Globals:
+# TEST_STATUS
+# TEST_NAME
+# TEST_CASE
+#######################################
+assert_command_succeeded() {
+ if (( TEST_STATUS != 0 )); then
+ echo "[ FAILED ] ${TEST_NAME}.${TEST_CASE}"
+ exit 1
+ fi
+}
+
+#######################################
+# Asserts that the outcome of the latest test command is not 0.
+#
+# If not, it terminates the test execution.
+#
+# Globals:
+# TEST_STATUS
+# TEST_NAME
+# TEST_CASE
+#######################################
+assert_command_failed() {
+ if (( TEST_STATUS == 0 )); then
+ echo "[ FAILED ] ${TEST_NAME}.${TEST_CASE}"
+ exit 1
+ fi
+}
+
+#######################################
+# Starts a new test case; records the test case name to TEST_CASE.
+#
+# Globals:
+# TEST_NAME
+# TEST_CASE
+# Arguments:
+# test_case: The name of the test case.
+#######################################
+start_test_case() {
+ TEST_CASE="$1"
+ echo "[ RUN ] ${TEST_NAME}.${TEST_CASE}"
+}
+
+#######################################
+# Ends a test case printing a success message.
+#
+# Globals:
+# TEST_NAME
+# TEST_CASE
+#######################################
+end_test_case() {
+ echo "[ OK ] ${TEST_NAME}.${TEST_CASE}"
+}
+
+#############################################################################
+
+start_test_case "encrypt"
+
+# Run encryption.
+test_command "${CLI}" \
+ --mode encrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}" \
+ --output_filename "${DATA_FILE}.encrypted"
+assert_command_succeeded
+
+end_test_case
+
+#############################################################################
+
+start_test_case "decrypt"
+
+# Run decryption.
+test_command "${CLI}" \
+ --mode decrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}.encrypted" \
+ --output_filename "${DATA_FILE}.decrypted"
+assert_command_succeeded
+
+test_command cmp -s "${DATA_FILE}" "${DATA_FILE}.decrypted"
+assert_command_succeeded
+
+end_test_case
+
+#############################################################################
+
+start_test_case "encrypt_decrypt_fails_with_modified_ciphertext"
+
+# Run encryption
+test_command "${CLI}" \
+ --mode encrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}" \
+ --output_filename "${DATA_FILE}.encrypted"
+assert_command_succeeded
+
+# Modify ciphertext.
+echo "modified" >> "${DATA_FILE}.encrypted"
+
+# Run decryption.
+test_command "${CLI}" \
+ --mode decrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}.encrypted" \
+ --output_filename "${DATA_FILE}.decrypted"
+assert_command_failed
+
+end_test_case
+
+#############################################################################
+
+start_test_case "encrypt_decrypt_succeeds_with_associated_data"
+
+# Run encryption.
+ASSOCIATED_DATA="header information"
+test_command "${CLI}" \
+ --mode encrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}" \
+ --output_filename "${DATA_FILE}.encrypted" \
+ --associated_data "${ASSOCIATED_DATA}"
+assert_command_succeeded
+
+# Run decryption.
+test_command "${CLI}" \
+ --mode decrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}.encrypted" \
+ --output_filename "${DATA_FILE}.decrypted" \
+ --associated_data "${ASSOCIATED_DATA}"
+assert_command_succeeded
+
+cmp --silent "${DATA_FILE}" "${DATA_FILE}.decrypted"
+assert_command_succeeded
+
+end_test_case
+
+#############################################################################
+
+start_test_case "encrypt_decrypt_fails_with_modified_associated_data"
+
+# Run encryption.
+ASSOCIATED_DATA="header information"
+test_command "${CLI}" \
+ --mode encrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}" \
+ --output_filename "${DATA_FILE}.encrypted" \
+ --associated_data "${ASSOCIATED_DATA}"
+assert_command_succeeded
+
+# Run decryption.
+MODIFIED_ASSOCIATED_DATA="modified header information"
+test_command "${CLI}" \
+ --mode decrypt \
+ --keyset_filename "${KEYSET_FILE}" \
+ --input_filename "${DATA_FILE}.encrypted" \
+ --output_filename "${DATA_FILE}.decrypted" \
+ --associated_data "${MODIFIED_ASSOCIATED_DATA}"
+assert_command_failed
+
+end_test_case
diff --git a/cc/examples/daead/deterministic_aead_test_keyset.json b/cc/examples/daead/deterministic_aead_test_keyset.json
new file mode 100644
index 000000000..74cd75f56
--- /dev/null
+++ b/cc/examples/daead/deterministic_aead_test_keyset.json
@@ -0,0 +1,15 @@
+{
+ "primaryKeyId": 1184417862,
+ "key": [
+ {
+ "keyData": {
+ "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey",
+ "value": "EkAbqs8wuMAXvuqU9FVOW9VvG9kE9P3aI5qjnkGvNTeRh/Cxoh06kosU5R9jRCHCkdMgnOSHMtfIKkQj5exuhesH",
+ "keyMaterialType": "SYMMETRIC"
+ },
+ "status": "ENABLED",
+ "keyId": 1184417862,
+ "outputPrefixType": "TINK"
+ }
+ ]
+}