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