xref: /aosp_15_r20/external/tink/cc/subtle/streaming_mac_impl.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang // Copyright 2019 Google LLC
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang //     http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang 
17*e7b1675dSTing-Kang Chang #include "tink/subtle/streaming_mac_impl.h"
18*e7b1675dSTing-Kang Chang 
19*e7b1675dSTing-Kang Chang #include <algorithm>
20*e7b1675dSTing-Kang Chang #include <memory>
21*e7b1675dSTing-Kang Chang #include <string>
22*e7b1675dSTing-Kang Chang #include <utility>
23*e7b1675dSTing-Kang Chang 
24*e7b1675dSTing-Kang Chang #include "absl/memory/memory.h"
25*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
26*e7b1675dSTing-Kang Chang #include "openssl/crypto.h"
27*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
28*e7b1675dSTing-Kang Chang 
29*e7b1675dSTing-Kang Chang namespace crypto {
30*e7b1675dSTing-Kang Chang namespace tink {
31*e7b1675dSTing-Kang Chang namespace subtle {
32*e7b1675dSTing-Kang Chang 
33*e7b1675dSTing-Kang Chang namespace {
34*e7b1675dSTing-Kang Chang constexpr size_t kBufferSize = 4096;
35*e7b1675dSTing-Kang Chang }
36*e7b1675dSTing-Kang Chang 
37*e7b1675dSTing-Kang Chang class ComputeMacOutputStream : public OutputStreamWithResult<std::string> {
38*e7b1675dSTing-Kang Chang  public:
ComputeMacOutputStream(std::unique_ptr<StatefulMac> mac)39*e7b1675dSTing-Kang Chang   explicit ComputeMacOutputStream(std::unique_ptr<StatefulMac> mac)
40*e7b1675dSTing-Kang Chang       : status_(util::OkStatus()),
41*e7b1675dSTing-Kang Chang         mac_(std::move(mac)),
42*e7b1675dSTing-Kang Chang         position_(0),
43*e7b1675dSTing-Kang Chang         buffer_position_(0),
44*e7b1675dSTing-Kang Chang         buffer_("") {
45*e7b1675dSTing-Kang Chang     buffer_.resize(kBufferSize);
46*e7b1675dSTing-Kang Chang   }
47*e7b1675dSTing-Kang Chang 
48*e7b1675dSTing-Kang Chang   util::StatusOr<int> NextBuffer(void** buffer) override;
49*e7b1675dSTing-Kang Chang   util::StatusOr<std::string> CloseStreamAndComputeResult() override;
50*e7b1675dSTing-Kang Chang   void BackUp(int count) override;
Position() const51*e7b1675dSTing-Kang Chang   int64_t Position() const override { return position_; }
52*e7b1675dSTing-Kang Chang 
53*e7b1675dSTing-Kang Chang  private:
54*e7b1675dSTing-Kang Chang   void WriteIntoMac();
55*e7b1675dSTing-Kang Chang 
56*e7b1675dSTing-Kang Chang   util::Status status_;
57*e7b1675dSTing-Kang Chang   const std::unique_ptr<StatefulMac> mac_;
58*e7b1675dSTing-Kang Chang   int64_t position_;
59*e7b1675dSTing-Kang Chang   int buffer_position_;
60*e7b1675dSTing-Kang Chang   std::string buffer_;
61*e7b1675dSTing-Kang Chang };
62*e7b1675dSTing-Kang Chang 
63*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<OutputStreamWithResult<std::string>>>
NewComputeMacOutputStream() const64*e7b1675dSTing-Kang Chang StreamingMacImpl::NewComputeMacOutputStream() const {
65*e7b1675dSTing-Kang Chang   util::StatusOr<std::unique_ptr<StatefulMac>> mac_status =
66*e7b1675dSTing-Kang Chang       mac_factory_->Create();
67*e7b1675dSTing-Kang Chang 
68*e7b1675dSTing-Kang Chang   if (!mac_status.ok()) {
69*e7b1675dSTing-Kang Chang     return mac_status.status();
70*e7b1675dSTing-Kang Chang   }
71*e7b1675dSTing-Kang Chang 
72*e7b1675dSTing-Kang Chang   std::unique_ptr<OutputStreamWithResult<std::string>> string_to_return =
73*e7b1675dSTing-Kang Chang       absl::make_unique<ComputeMacOutputStream>(std::move(mac_status.value()));
74*e7b1675dSTing-Kang Chang   return std::move(string_to_return);
75*e7b1675dSTing-Kang Chang }
76*e7b1675dSTing-Kang Chang 
NextBuffer(void ** buffer)77*e7b1675dSTing-Kang Chang util::StatusOr<int> ComputeMacOutputStream::NextBuffer(void** buffer) {
78*e7b1675dSTing-Kang Chang   if (!status_.ok()) {
79*e7b1675dSTing-Kang Chang     return status_;
80*e7b1675dSTing-Kang Chang   }
81*e7b1675dSTing-Kang Chang   WriteIntoMac();
82*e7b1675dSTing-Kang Chang   *buffer = &buffer_[0];
83*e7b1675dSTing-Kang Chang   position_ += kBufferSize;
84*e7b1675dSTing-Kang Chang   buffer_position_ = kBufferSize;
85*e7b1675dSTing-Kang Chang   return buffer_position_;
86*e7b1675dSTing-Kang Chang }
87*e7b1675dSTing-Kang Chang 
88*e7b1675dSTing-Kang Chang util::StatusOr<std::string>
CloseStreamAndComputeResult()89*e7b1675dSTing-Kang Chang ComputeMacOutputStream::CloseStreamAndComputeResult() {
90*e7b1675dSTing-Kang Chang   if (!status_.ok()) {
91*e7b1675dSTing-Kang Chang     return status_;
92*e7b1675dSTing-Kang Chang   }
93*e7b1675dSTing-Kang Chang   WriteIntoMac();
94*e7b1675dSTing-Kang Chang   status_ =
95*e7b1675dSTing-Kang Chang       util::Status(absl::StatusCode::kFailedPrecondition, "Stream Closed");
96*e7b1675dSTing-Kang Chang   return mac_->Finalize();
97*e7b1675dSTing-Kang Chang }
98*e7b1675dSTing-Kang Chang 
BackUp(int count)99*e7b1675dSTing-Kang Chang void ComputeMacOutputStream::BackUp(int count) {
100*e7b1675dSTing-Kang Chang   count = std::min(count, buffer_position_);
101*e7b1675dSTing-Kang Chang   buffer_position_ -= count;
102*e7b1675dSTing-Kang Chang   position_ -= count;
103*e7b1675dSTing-Kang Chang }
104*e7b1675dSTing-Kang Chang 
105*e7b1675dSTing-Kang Chang // Writes the data in buffer_ into mac_, and clears buffer_.
WriteIntoMac()106*e7b1675dSTing-Kang Chang void ComputeMacOutputStream::WriteIntoMac() {
107*e7b1675dSTing-Kang Chang   // Remove the suffix of the buffer (all data after buffer_position_).
108*e7b1675dSTing-Kang Chang   status_ = mac_->Update(absl::string_view(buffer_.data(), buffer_position_));
109*e7b1675dSTing-Kang Chang 
110*e7b1675dSTing-Kang Chang   // Clear the buffer, so that any sensitive information that
111*e7b1675dSTing-Kang Chang   // was written to the buffer cannot be accessed later.
112*e7b1675dSTing-Kang Chang   // Write buffer_position_ number of 0's to the buffer, starting from idx 0.
113*e7b1675dSTing-Kang Chang   buffer_.replace(0, buffer_position_, buffer_position_, 0);
114*e7b1675dSTing-Kang Chang }
115*e7b1675dSTing-Kang Chang 
116*e7b1675dSTing-Kang Chang class VerifyMacOutputStream : public OutputStreamWithResult<util::Status> {
117*e7b1675dSTing-Kang Chang  public:
VerifyMacOutputStream(const std::string & expected,std::unique_ptr<StatefulMac> mac)118*e7b1675dSTing-Kang Chang   VerifyMacOutputStream(const std::string& expected,
119*e7b1675dSTing-Kang Chang                         std::unique_ptr<StatefulMac> mac)
120*e7b1675dSTing-Kang Chang       : status_(util::OkStatus()),
121*e7b1675dSTing-Kang Chang         mac_(std::move(mac)),
122*e7b1675dSTing-Kang Chang         position_(0),
123*e7b1675dSTing-Kang Chang         buffer_position_(0),
124*e7b1675dSTing-Kang Chang         buffer_(""),
125*e7b1675dSTing-Kang Chang         expected_(expected) {
126*e7b1675dSTing-Kang Chang     buffer_.resize(kBufferSize);
127*e7b1675dSTing-Kang Chang   }
128*e7b1675dSTing-Kang Chang 
129*e7b1675dSTing-Kang Chang   util::StatusOr<int> NextBuffer(void** buffer) override;
130*e7b1675dSTing-Kang Chang 
131*e7b1675dSTing-Kang Chang   util::Status CloseStreamAndComputeResult() override;
132*e7b1675dSTing-Kang Chang 
133*e7b1675dSTing-Kang Chang   void BackUp(int count) override;
Position() const134*e7b1675dSTing-Kang Chang   int64_t Position() const override { return position_; }
135*e7b1675dSTing-Kang Chang 
136*e7b1675dSTing-Kang Chang  private:
137*e7b1675dSTing-Kang Chang   void WriteIntoMac();
138*e7b1675dSTing-Kang Chang 
139*e7b1675dSTing-Kang Chang   // Stream status: Initialized as OK, and
140*e7b1675dSTing-Kang Chang   // changed to ERROR:FAILED_PRECONDITION when the stream is closed.
141*e7b1675dSTing-Kang Chang   util::Status status_;
142*e7b1675dSTing-Kang Chang   std::unique_ptr<StatefulMac> mac_;
143*e7b1675dSTing-Kang Chang   int64_t position_;
144*e7b1675dSTing-Kang Chang   int buffer_position_;
145*e7b1675dSTing-Kang Chang   std::string buffer_;
146*e7b1675dSTing-Kang Chang   std::string expected_;
147*e7b1675dSTing-Kang Chang };
148*e7b1675dSTing-Kang Chang 
NextBuffer(void ** buffer)149*e7b1675dSTing-Kang Chang util::StatusOr<int> VerifyMacOutputStream::NextBuffer(void** buffer) {
150*e7b1675dSTing-Kang Chang   if (!status_.ok()) {
151*e7b1675dSTing-Kang Chang     return status_;
152*e7b1675dSTing-Kang Chang   }
153*e7b1675dSTing-Kang Chang   WriteIntoMac();
154*e7b1675dSTing-Kang Chang   *buffer = &buffer_[0];
155*e7b1675dSTing-Kang Chang   position_ += kBufferSize;
156*e7b1675dSTing-Kang Chang   buffer_position_ = kBufferSize;
157*e7b1675dSTing-Kang Chang   return buffer_position_;
158*e7b1675dSTing-Kang Chang }
159*e7b1675dSTing-Kang Chang 
CloseStreamAndComputeResult()160*e7b1675dSTing-Kang Chang util::Status VerifyMacOutputStream::CloseStreamAndComputeResult() {
161*e7b1675dSTing-Kang Chang   if (!status_.ok()) {
162*e7b1675dSTing-Kang Chang     return status_;
163*e7b1675dSTing-Kang Chang   }
164*e7b1675dSTing-Kang Chang   WriteIntoMac();
165*e7b1675dSTing-Kang Chang   status_ =
166*e7b1675dSTing-Kang Chang       util::Status(absl::StatusCode::kFailedPrecondition, "Stream Closed");
167*e7b1675dSTing-Kang Chang   util::StatusOr<std::string> mac_actual = mac_->Finalize();
168*e7b1675dSTing-Kang Chang   if (!mac_actual.ok()) {
169*e7b1675dSTing-Kang Chang     return mac_actual.status();
170*e7b1675dSTing-Kang Chang   }
171*e7b1675dSTing-Kang Chang   if (mac_actual->size() != expected_.size()) {
172*e7b1675dSTing-Kang Chang     return absl::InvalidArgumentError(
173*e7b1675dSTing-Kang Chang         absl::StrCat("Invalid MAC size; expected ", expected_.size(), ", got ",
174*e7b1675dSTing-Kang Chang                      mac_actual->size()));
175*e7b1675dSTing-Kang Chang   }
176*e7b1675dSTing-Kang Chang   if (!CRYPTO_memcmp(mac_actual->data(), expected_.data(),
177*e7b1675dSTing-Kang Chang                      mac_actual->size())) {
178*e7b1675dSTing-Kang Chang     return util::OkStatus();
179*e7b1675dSTing-Kang Chang   }
180*e7b1675dSTing-Kang Chang   return absl::InvalidArgumentError("Incorrect MAC");
181*e7b1675dSTing-Kang Chang }
182*e7b1675dSTing-Kang Chang 
BackUp(int count)183*e7b1675dSTing-Kang Chang void VerifyMacOutputStream::BackUp(int count) {
184*e7b1675dSTing-Kang Chang   count = std::min(count, buffer_position_);
185*e7b1675dSTing-Kang Chang   buffer_position_ -= count;
186*e7b1675dSTing-Kang Chang   position_ -= count;
187*e7b1675dSTing-Kang Chang }
188*e7b1675dSTing-Kang Chang 
189*e7b1675dSTing-Kang Chang // Writes the data in buffer_ into mac_, and clears buffer_.
WriteIntoMac()190*e7b1675dSTing-Kang Chang void VerifyMacOutputStream::WriteIntoMac() {
191*e7b1675dSTing-Kang Chang   // Remove the suffix of the buffer (all data after buffer_position_).
192*e7b1675dSTing-Kang Chang   status_ = mac_->Update(absl::string_view(buffer_.data(), buffer_position_));
193*e7b1675dSTing-Kang Chang 
194*e7b1675dSTing-Kang Chang   // Clear the buffer, so that any sensitive information that
195*e7b1675dSTing-Kang Chang   // was written to the buffer cannot be accessed later.
196*e7b1675dSTing-Kang Chang   // Write buffer_position_ number of 0's to the buffer, starting from idx 0.
197*e7b1675dSTing-Kang Chang   buffer_.replace(0, buffer_position_, buffer_position_, 0);
198*e7b1675dSTing-Kang Chang }
199*e7b1675dSTing-Kang Chang 
200*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<OutputStreamWithResult<util::Status>>>
NewVerifyMacOutputStream(const std::string & mac_value) const201*e7b1675dSTing-Kang Chang StreamingMacImpl::NewVerifyMacOutputStream(const std::string& mac_value) const {
202*e7b1675dSTing-Kang Chang   util::StatusOr<std::unique_ptr<StatefulMac>> mac_status =
203*e7b1675dSTing-Kang Chang       mac_factory_->Create();
204*e7b1675dSTing-Kang Chang   if (!mac_status.ok()) {
205*e7b1675dSTing-Kang Chang     return mac_status.status();
206*e7b1675dSTing-Kang Chang   }
207*e7b1675dSTing-Kang Chang   return std::unique_ptr<OutputStreamWithResult<util::Status>>(
208*e7b1675dSTing-Kang Chang       absl::make_unique<VerifyMacOutputStream>(mac_value,
209*e7b1675dSTing-Kang Chang                                                std::move(mac_status.value())));
210*e7b1675dSTing-Kang Chang }
211*e7b1675dSTing-Kang Chang }  // namespace subtle
212*e7b1675dSTing-Kang Chang }  // namespace tink
213*e7b1675dSTing-Kang Chang }  // namespace crypto
214