xref: /aosp_15_r20/external/tink/cc/subtle/encrypt_then_authenticate.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang // Copyright 2017 Google Inc.
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/encrypt_then_authenticate.h"
18*e7b1675dSTing-Kang Chang 
19*e7b1675dSTing-Kang Chang #include <cstdint>
20*e7b1675dSTing-Kang Chang #include <memory>
21*e7b1675dSTing-Kang Chang #include <string>
22*e7b1675dSTing-Kang Chang #include <utility>
23*e7b1675dSTing-Kang Chang #include <vector>
24*e7b1675dSTing-Kang Chang 
25*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
26*e7b1675dSTing-Kang Chang #include "absl/strings/str_cat.h"
27*e7b1675dSTing-Kang Chang #include "absl/strings/string_view.h"
28*e7b1675dSTing-Kang Chang #include "tink/aead.h"
29*e7b1675dSTing-Kang Chang #include "tink/internal/util.h"
30*e7b1675dSTing-Kang Chang #include "tink/mac.h"
31*e7b1675dSTing-Kang Chang #include "tink/subtle/ind_cpa_cipher.h"
32*e7b1675dSTing-Kang Chang #include "tink/util/errors.h"
33*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
34*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h"
35*e7b1675dSTing-Kang Chang 
36*e7b1675dSTing-Kang Chang namespace crypto {
37*e7b1675dSTing-Kang Chang namespace tink {
38*e7b1675dSTing-Kang Chang namespace subtle {
39*e7b1675dSTing-Kang Chang 
longToBigEndianStr(uint64_t value)40*e7b1675dSTing-Kang Chang static std::string longToBigEndianStr(uint64_t value) {
41*e7b1675dSTing-Kang Chang   uint8_t bytes[8];
42*e7b1675dSTing-Kang Chang   for (int i = sizeof(bytes) - 1; i >= 0; i--) {
43*e7b1675dSTing-Kang Chang     bytes[i] = value & 0xff;
44*e7b1675dSTing-Kang Chang     value >>= 8;
45*e7b1675dSTing-Kang Chang   }
46*e7b1675dSTing-Kang Chang   return std::string(reinterpret_cast<const char*>(&bytes[0]), sizeof(bytes));
47*e7b1675dSTing-Kang Chang }
48*e7b1675dSTing-Kang Chang 
New(std::unique_ptr<IndCpaCipher> ind_cpa_cipher,std::unique_ptr<Mac> mac,uint8_t tag_size)49*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<Aead>> EncryptThenAuthenticate::New(
50*e7b1675dSTing-Kang Chang     std::unique_ptr<IndCpaCipher> ind_cpa_cipher, std::unique_ptr<Mac> mac,
51*e7b1675dSTing-Kang Chang     uint8_t tag_size) {
52*e7b1675dSTing-Kang Chang   if (tag_size < kMinTagSizeInBytes) {
53*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInvalidArgument,
54*e7b1675dSTing-Kang Chang                         "tag size too small");
55*e7b1675dSTing-Kang Chang   }
56*e7b1675dSTing-Kang Chang   std::unique_ptr<Aead> aead(new EncryptThenAuthenticate(
57*e7b1675dSTing-Kang Chang       std::move(ind_cpa_cipher), std::move(mac), tag_size));
58*e7b1675dSTing-Kang Chang   return std::move(aead);
59*e7b1675dSTing-Kang Chang }
60*e7b1675dSTing-Kang Chang 
Encrypt(absl::string_view plaintext,absl::string_view associated_data) const61*e7b1675dSTing-Kang Chang util::StatusOr<std::string> EncryptThenAuthenticate::Encrypt(
62*e7b1675dSTing-Kang Chang     absl::string_view plaintext, absl::string_view associated_data) const {
63*e7b1675dSTing-Kang Chang   // BoringSSL expects a non-null pointer for plaintext and associated_data,
64*e7b1675dSTing-Kang Chang   // regardless of whether the size is 0.
65*e7b1675dSTing-Kang Chang   plaintext = internal::EnsureStringNonNull(plaintext);
66*e7b1675dSTing-Kang Chang   associated_data = internal::EnsureStringNonNull(associated_data);
67*e7b1675dSTing-Kang Chang 
68*e7b1675dSTing-Kang Chang   uint64_t associated_data_size_in_bytes = associated_data.size();
69*e7b1675dSTing-Kang Chang   uint64_t associated_data_size_in_bits = associated_data_size_in_bytes * 8;
70*e7b1675dSTing-Kang Chang   if (associated_data_size_in_bits / 8 !=
71*e7b1675dSTing-Kang Chang       associated_data_size_in_bytes /* overflow occured! */) {
72*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInvalidArgument,
73*e7b1675dSTing-Kang Chang                         "associated data too long");
74*e7b1675dSTing-Kang Chang   }
75*e7b1675dSTing-Kang Chang 
76*e7b1675dSTing-Kang Chang   auto ciphertext = ind_cpa_cipher_->Encrypt(plaintext);
77*e7b1675dSTing-Kang Chang   if (!ciphertext.ok()) {
78*e7b1675dSTing-Kang Chang     return ciphertext.status();
79*e7b1675dSTing-Kang Chang   }
80*e7b1675dSTing-Kang Chang   auto tag = mac_->ComputeMac(
81*e7b1675dSTing-Kang Chang       absl::StrCat(associated_data, *ciphertext,
82*e7b1675dSTing-Kang Chang                    longToBigEndianStr(associated_data_size_in_bits)));
83*e7b1675dSTing-Kang Chang   if (!tag.ok()) {
84*e7b1675dSTing-Kang Chang     return tag.status();
85*e7b1675dSTing-Kang Chang   }
86*e7b1675dSTing-Kang Chang   if (tag->size() != tag_size_) {
87*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInternal, "invalid tag size");
88*e7b1675dSTing-Kang Chang   }
89*e7b1675dSTing-Kang Chang   return ciphertext->append(tag.value());
90*e7b1675dSTing-Kang Chang }
91*e7b1675dSTing-Kang Chang 
Decrypt(absl::string_view ciphertext,absl::string_view associated_data) const92*e7b1675dSTing-Kang Chang util::StatusOr<std::string> EncryptThenAuthenticate::Decrypt(
93*e7b1675dSTing-Kang Chang     absl::string_view ciphertext, absl::string_view associated_data) const {
94*e7b1675dSTing-Kang Chang   // BoringSSL expects a non-null pointer for associated_data,
95*e7b1675dSTing-Kang Chang   // regardless of whether the size is 0.
96*e7b1675dSTing-Kang Chang   associated_data = internal::EnsureStringNonNull(associated_data);
97*e7b1675dSTing-Kang Chang 
98*e7b1675dSTing-Kang Chang   if (ciphertext.size() < tag_size_) {
99*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInvalidArgument,
100*e7b1675dSTing-Kang Chang                         "ciphertext too short");
101*e7b1675dSTing-Kang Chang   }
102*e7b1675dSTing-Kang Chang 
103*e7b1675dSTing-Kang Chang   uint64_t associated_data_size_in_bytes = associated_data.size();
104*e7b1675dSTing-Kang Chang   uint64_t associated_data_size_in_bits = associated_data_size_in_bytes * 8;
105*e7b1675dSTing-Kang Chang   if (associated_data_size_in_bits / 8 !=
106*e7b1675dSTing-Kang Chang       associated_data_size_in_bytes /* overflow occured! */) {
107*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInvalidArgument,
108*e7b1675dSTing-Kang Chang                         "additional data too long");
109*e7b1675dSTing-Kang Chang   }
110*e7b1675dSTing-Kang Chang 
111*e7b1675dSTing-Kang Chang   auto payload = ciphertext.substr(0, ciphertext.size() - tag_size_);
112*e7b1675dSTing-Kang Chang   auto tag = ciphertext.substr(ciphertext.size() - tag_size_, tag_size_);
113*e7b1675dSTing-Kang Chang 
114*e7b1675dSTing-Kang Chang   auto verified = mac_->VerifyMac(
115*e7b1675dSTing-Kang Chang       tag, absl::StrCat(associated_data, payload,
116*e7b1675dSTing-Kang Chang                         longToBigEndianStr(associated_data_size_in_bits)));
117*e7b1675dSTing-Kang Chang   if (!verified.ok()) {
118*e7b1675dSTing-Kang Chang     return verified;
119*e7b1675dSTing-Kang Chang   }
120*e7b1675dSTing-Kang Chang 
121*e7b1675dSTing-Kang Chang   auto pt = ind_cpa_cipher_->Decrypt(payload);
122*e7b1675dSTing-Kang Chang   if (!pt.ok()) {
123*e7b1675dSTing-Kang Chang     return pt.status();
124*e7b1675dSTing-Kang Chang   }
125*e7b1675dSTing-Kang Chang 
126*e7b1675dSTing-Kang Chang   return pt.value();
127*e7b1675dSTing-Kang Chang }
128*e7b1675dSTing-Kang Chang 
129*e7b1675dSTing-Kang Chang }  // namespace subtle
130*e7b1675dSTing-Kang Chang }  // namespace tink
131*e7b1675dSTing-Kang Chang }  // namespace crypto
132