xref: /aosp_15_r20/external/tink/cc/mac/internal/chunked_mac_wrapper.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2022 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 
17 #include "tink/mac/internal/chunked_mac_wrapper.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/status/status.h"
25 #include "absl/strings/str_cat.h"
26 #include "tink/chunked_mac.h"
27 #include "tink/crypto_format.h"
28 #include "tink/internal/util.h"
29 #include "tink/primitive_set.h"
30 #include "tink/util/status.h"
31 #include "tink/util/statusor.h"
32 #include "proto/tink.pb.h"
33 
34 namespace crypto {
35 namespace tink {
36 namespace internal {
37 namespace {
38 
39 using ::google::crypto::tink::OutputPrefixType;
40 
41 class ChunkedMacComputationSetWrapper : public ChunkedMacComputation {
42  public:
ChunkedMacComputationSetWrapper(std::unique_ptr<ChunkedMacComputation> computation,absl::string_view tag_prefix,OutputPrefixType output_prefix_type)43   explicit ChunkedMacComputationSetWrapper(
44       std::unique_ptr<ChunkedMacComputation> computation,
45       absl::string_view tag_prefix, OutputPrefixType output_prefix_type)
46       : computation_(std::move(computation)),
47         tag_prefix_(tag_prefix),
48         output_prefix_type_(output_prefix_type) {}
49 
50   util::Status Update(absl::string_view data) override;
51 
52   util::StatusOr<std::string> ComputeMac() override;
53 
54  private:
55   const std::unique_ptr<ChunkedMacComputation> computation_;
56   const std::string tag_prefix_;
57   const OutputPrefixType output_prefix_type_;
58 };
59 
Update(absl::string_view data)60 util::Status ChunkedMacComputationSetWrapper::Update(absl::string_view data) {
61   return computation_->Update(data);
62 }
63 
ComputeMac()64 util::StatusOr<std::string> ChunkedMacComputationSetWrapper::ComputeMac() {
65   if (output_prefix_type_ == OutputPrefixType::LEGACY) {
66     util::Status append_status = computation_->Update(std::string("\x00", 1));
67     if (!append_status.ok()) return append_status;
68   }
69   util::StatusOr<std::string> raw_tag = computation_->ComputeMac();
70   if (!raw_tag.ok()) return raw_tag.status();
71   return absl::StrCat(tag_prefix_, *raw_tag);
72 }
73 
74 class ChunkedMacVerificationWithPrefixType : public ChunkedMacVerification {
75  public:
ChunkedMacVerificationWithPrefixType(std::unique_ptr<ChunkedMacVerification> verification,OutputPrefixType output_prefix_type)76   explicit ChunkedMacVerificationWithPrefixType(
77       std::unique_ptr<ChunkedMacVerification> verification,
78       OutputPrefixType output_prefix_type)
79       : verification_(std::move(verification)),
80         output_prefix_type_(output_prefix_type) {}
81 
82   util::Status Update(absl::string_view data) override;
83 
84   util::Status VerifyMac() override;
85 
86  private:
87   const std::unique_ptr<ChunkedMacVerification> verification_;
88   const OutputPrefixType output_prefix_type_;
89 };
90 
Update(absl::string_view data)91 util::Status ChunkedMacVerificationWithPrefixType::Update(
92     absl::string_view data) {
93   return verification_->Update(data);
94 }
95 
VerifyMac()96 util::Status ChunkedMacVerificationWithPrefixType::VerifyMac() {
97   if (output_prefix_type_ == OutputPrefixType::LEGACY) {
98     util::Status append_status = verification_->Update(std::string("\x00", 1));
99     if (!append_status.ok()) return append_status;
100   }
101   return verification_->VerifyMac();
102 }
103 
104 class ChunkedMacVerificationSetWrapper : public ChunkedMacVerification {
105  public:
ChunkedMacVerificationSetWrapper(std::unique_ptr<std::vector<std::unique_ptr<ChunkedMacVerificationWithPrefixType>>> verifications)106   explicit ChunkedMacVerificationSetWrapper(
107       std::unique_ptr<
108           std::vector<std::unique_ptr<ChunkedMacVerificationWithPrefixType>>>
109           verifications)
110       : verifications_(std::move(verifications)) {}
111 
112   util::Status Update(absl::string_view data) override;
113 
114   util::Status VerifyMac() override;
115 
116  private:
117   const std::unique_ptr<
118       std::vector<std::unique_ptr<ChunkedMacVerificationWithPrefixType>>>
119       verifications_;
120 };
121 
Update(absl::string_view data)122 util::Status ChunkedMacVerificationSetWrapper::Update(absl::string_view data) {
123   util::Status status =
124       util::Status(absl::StatusCode::kUnknown, "Update failed.");
125   for (auto& verification : *verifications_) {
126     util::Status individual_update_status = verification->Update(data);
127     if (individual_update_status.ok()) {
128       // At least one update succeeded.
129       status = util::OkStatus();
130     }
131   }
132   return status;
133 }
134 
VerifyMac()135 util::Status ChunkedMacVerificationSetWrapper::VerifyMac() {
136   for (auto& verification : *verifications_) {
137     absl::Status status = verification->VerifyMac();
138     if (status.ok()) {
139       // One of the verifications succeeded.
140       return status;
141     }
142   }
143   return util::Status(absl::StatusCode::kUnknown, "Verification failed.");
144 }
145 
146 class ChunkedMacSetWrapper : public ChunkedMac {
147  public:
ChunkedMacSetWrapper(std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set)148   explicit ChunkedMacSetWrapper(
149       std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set)
150       : mac_set_(std::move(mac_set)) {}
151 
152   util::StatusOr<std::unique_ptr<ChunkedMacComputation>> CreateComputation()
153       const override;
154 
155   util::StatusOr<std::unique_ptr<ChunkedMacVerification>> CreateVerification(
156       absl::string_view tag) const override;
157 
158   ~ChunkedMacSetWrapper() override = default;
159 
160  private:
161   std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set_;
162 };
163 
Validate(PrimitiveSet<ChunkedMac> * mac_set)164 util::Status Validate(PrimitiveSet<ChunkedMac>* mac_set) {
165   if (mac_set == nullptr) {
166     return util::Status(absl::StatusCode::kInternal,
167                         "mac_set must be non-NULL");
168   }
169   if (mac_set->get_primary() == nullptr) {
170     return util::Status(absl::StatusCode::kInvalidArgument,
171                         "mac_set has no primary");
172   }
173   return util::OkStatus();
174 }
175 
176 util::StatusOr<std::unique_ptr<ChunkedMacComputation>>
CreateComputation() const177 ChunkedMacSetWrapper::CreateComputation() const {
178   const PrimitiveSet<ChunkedMac>::Entry<ChunkedMac>* primary =
179       mac_set_->get_primary();
180   util::StatusOr<std::unique_ptr<ChunkedMacComputation>> computation =
181       primary->get_primitive().CreateComputation();
182   if (!computation.ok()) return computation.status();
183   return {absl::make_unique<ChunkedMacComputationSetWrapper>(
184       *std::move(computation), primary->get_identifier(),
185       primary->get_output_prefix_type())};
186 }
187 
188 util::StatusOr<std::unique_ptr<ChunkedMacVerification>>
CreateVerification(absl::string_view tag) const189 ChunkedMacSetWrapper::CreateVerification(absl::string_view tag) const {
190   tag = internal::EnsureStringNonNull(tag);
191 
192   auto verifications = absl::make_unique<
193       std::vector<std::unique_ptr<ChunkedMacVerificationWithPrefixType>>>();
194 
195   // Create verifications for all non-RAW keys with matching identifiers by
196   // removing prefix.
197   if (tag.length() > CryptoFormat::kNonRawPrefixSize) {
198     absl::string_view key_id = tag.substr(0, CryptoFormat::kNonRawPrefixSize);
199     auto primitives_result = mac_set_->get_primitives(key_id);
200     if (primitives_result.ok()) {
201       absl::string_view raw_tag = tag.substr(CryptoFormat::kNonRawPrefixSize);
202       for (auto& mac_entry : *(primitives_result.value())) {
203         util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
204             mac_entry->get_primitive().CreateVerification(raw_tag);
205         if (verification.ok()) {
206           auto verification_with_prefix =
207               absl::make_unique<ChunkedMacVerificationWithPrefixType>(
208                   *std::move(verification),
209                   mac_entry->get_output_prefix_type());
210           verifications->push_back(std::move(verification_with_prefix));
211         }
212       }
213     }
214   }
215 
216   // Create verifications for all RAW keys by including prefix.
217   auto raw_primitives_result = mac_set_->get_raw_primitives();
218   if (raw_primitives_result.ok()) {
219     for (auto& mac_entry : *(raw_primitives_result.value())) {
220       util::StatusOr<std::unique_ptr<ChunkedMacVerification>> verification =
221           mac_entry->get_primitive().CreateVerification(tag);
222       if (verification.ok()) {
223         auto verification_with_prefix =
224             absl::make_unique<ChunkedMacVerificationWithPrefixType>(
225                 *std::move(verification), mac_entry->get_output_prefix_type());
226         verifications->push_back(std::move(verification_with_prefix));
227       }
228     }
229   }
230 
231   return {absl::make_unique<ChunkedMacVerificationSetWrapper>(
232       std::move(verifications))};
233 }
234 
235 }  // namespace
236 
Wrap(std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set) const237 util::StatusOr<std::unique_ptr<ChunkedMac>> ChunkedMacWrapper::Wrap(
238     std::unique_ptr<PrimitiveSet<ChunkedMac>> mac_set) const {
239   util::Status status = Validate(mac_set.get());
240   if (!status.ok()) return status;
241   return {absl::make_unique<ChunkedMacSetWrapper>(std::move(mac_set))};
242 }
243 
244 }  // namespace internal
245 }  // namespace tink
246 }  // namespace crypto
247