xref: /aosp_15_r20/external/tink/cc/examples/key_derivation/key_derivation_cli.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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