1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 // [START key-derivation-example]
17 // A command-line utility for testing Tink Key Derivation.
18 #include <iostream>
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "absl/flags/flag.h"
24 #include "absl/flags/parse.h"
25 #include "absl/log/check.h"
26 #include "tink/aead.h"
27 #include "tink/aead/aead_config.h"
28 #include "util/util.h"
29 #include "tink/keyderivation/key_derivation_config.h"
30 #include "tink/keyderivation/keyset_deriver.h"
31 #include "tink/keyset_handle.h"
32 #include "tink/util/status.h"
33
34 ABSL_FLAG(std::string, keyset_filename, "",
35 "File in JSON format containing keyset that derives an AEAD keyset");
36 ABSL_FLAG(std::string, salt_filename, "", "Salt file name");
37 ABSL_FLAG(std::string, derived_keyset_filename, "", "Derived keyset file name");
38
39 namespace {
40
41 using ::crypto::tink::Aead;
42 using ::crypto::tink::AeadConfig;
43 using ::crypto::tink::KeyDerivationConfig;
44 using ::crypto::tink::KeysetDeriver;
45 using ::crypto::tink::KeysetHandle;
46 using ::crypto::tink::util::OkStatus;
47 using ::crypto::tink::util::Status;
48 using ::crypto::tink::util::StatusOr;
49
ValidateParams()50 void ValidateParams() {
51 // [START_EXCLUDE]
52 CHECK(!absl::GetFlag(FLAGS_keyset_filename).empty())
53 << "Keyset file must be specified";
54 CHECK(!absl::GetFlag(FLAGS_salt_filename).empty())
55 << "Input file must be specified";
56 CHECK(!absl::GetFlag(FLAGS_derived_keyset_filename).empty())
57 << "Output file must be specified";
58 // [END_EXCLUDE]
59 }
60
61 // Verifies `handle` contains a valid AEAD primitive.
VerifyDerivedAeadKeyset(const KeysetHandle & handle)62 Status VerifyDerivedAeadKeyset(const KeysetHandle& handle) {
63 // [START_EXCLUDE]
64 StatusOr<std::unique_ptr<Aead>> aead = handle.GetPrimitive<Aead>();
65 if (!aead.ok()) return aead.status();
66
67 std::string plaintext = "plaintext";
68 std::string ad = "ad";
69 StatusOr<std::string> ciphertext = (*aead)->Encrypt(plaintext, ad);
70 if (!ciphertext.ok()) return ciphertext.status();
71
72 StatusOr<std::string> got = (*aead)->Decrypt(*ciphertext, ad);
73 if (!got.ok()) return got.status();
74
75 if (*got != plaintext) {
76 return Status(
77 absl::StatusCode::kInternal,
78 "AEAD obtained from derived keyset failed to decrypt correctly");
79 }
80 return OkStatus();
81 // [END_EXCLUDE]
82 }
83
84 } // namespace
85
86 namespace tink_cc_examples {
87
KeyDerivationCli(const std::string & keyset_filename,const std::string & salt_filename,const std::string & derived_keyset_filename)88 Status KeyDerivationCli(const std::string& keyset_filename,
89 const std::string& salt_filename,
90 const std::string& derived_keyset_filename) {
91 Status result = KeyDerivationConfig::Register();
92 if (!result.ok()) return result;
93 result = AeadConfig::Register();
94 if (!result.ok()) return result;
95
96 // Read keyset from file.
97 StatusOr<std::unique_ptr<KeysetHandle>> keyset_handle =
98 ReadJsonCleartextKeyset(keyset_filename);
99 if (!keyset_handle.ok()) return keyset_handle.status();
100
101 // Get the primitive.
102 StatusOr<std::unique_ptr<KeysetDeriver>> deriver =
103 (*keyset_handle)->GetPrimitive<KeysetDeriver>();
104 if (!deriver.ok()) return deriver.status();
105
106 // Read the salt.
107 StatusOr<std::string> salt_file_content = ReadFile(salt_filename);
108 if (!salt_file_content.ok()) return salt_file_content.status();
109
110 // Derive new keyset.
111 StatusOr<std::unique_ptr<KeysetHandle>> derived_handle =
112 (*deriver)->DeriveKeyset(*salt_file_content);
113 if (!derived_handle.ok()) return derived_handle.status();
114
115 Status status = VerifyDerivedAeadKeyset(**derived_handle);
116 if (!status.ok()) return status;
117
118 return WriteJsonCleartextKeyset(derived_keyset_filename, **derived_handle);
119 }
120
121 } // namespace tink_cc_examples
122
main(int argc,char ** argv)123 int main(int argc, char** argv) {
124 absl::ParseCommandLine(argc, argv);
125
126 ValidateParams();
127
128 std::string keyset_filename = absl::GetFlag(FLAGS_keyset_filename);
129 std::string salt_filename = absl::GetFlag(FLAGS_salt_filename);
130 std::string derived_keyset_filename =
131 absl::GetFlag(FLAGS_derived_keyset_filename);
132
133 std::clog << "Using keyset from file " << keyset_filename
134 << " to derive a new AEAD keyset with the salt in file "
135 << salt_filename << "." << std::endl;
136 std::clog << "The resulting derived keyset will be written to "
137 << derived_keyset_filename << "." << std::endl;
138
139 CHECK_OK(tink_cc_examples::KeyDerivationCli(keyset_filename, salt_filename,
140 derived_keyset_filename));
141 return 0;
142 }
143 // [END key-derivation-example]
144