xref: /aosp_15_r20/external/tink/cc/hybrid/hybrid_encrypt_wrapper.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2017 Google Inc.
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/hybrid/hybrid_encrypt_wrapper.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 
23 #include "absl/status/status.h"
24 #include "tink/crypto_format.h"
25 #include "tink/hybrid_encrypt.h"
26 #include "tink/internal/monitoring_util.h"
27 #include "tink/internal/registry_impl.h"
28 #include "tink/internal/util.h"
29 #include "tink/monitoring/monitoring.h"
30 #include "tink/primitive_set.h"
31 #include "tink/util/status.h"
32 #include "tink/util/statusor.h"
33 
34 namespace crypto {
35 namespace tink {
36 
37 namespace {
38 
39 constexpr absl::string_view kPrimitive = "hybrid_encrypt";
40 constexpr absl::string_view kEncryptApi = "encrypt";
41 
Validate(PrimitiveSet<HybridEncrypt> * hybrid_encrypt_set)42 util::Status Validate(PrimitiveSet<HybridEncrypt>* hybrid_encrypt_set) {
43   if (hybrid_encrypt_set == nullptr) {
44     return util::Status(absl::StatusCode::kInternal,
45                         "hybrid_encrypt_set must be non-NULL");
46   }
47   if (hybrid_encrypt_set->get_primary() == nullptr) {
48     return util::Status(absl::StatusCode::kInvalidArgument,
49                         "hybrid_encrypt_set has no primary");
50   }
51   return util::OkStatus();
52 }
53 
54 // Returns an HybridEncrypt-primitive that uses the primary
55 // HybridEncrypt-instance provided in 'hybrid_encrypt_set',
56 // which must be non-NULL (and must contain a primary instance).
57 class HybridEncryptSetWrapper : public HybridEncrypt {
58  public:
HybridEncryptSetWrapper(std::unique_ptr<PrimitiveSet<HybridEncrypt>> hybrid_encrypt_set,std::unique_ptr<MonitoringClient> monitoring_encryption_client=nullptr)59   explicit HybridEncryptSetWrapper(
60       std::unique_ptr<PrimitiveSet<HybridEncrypt>> hybrid_encrypt_set,
61       std::unique_ptr<MonitoringClient> monitoring_encryption_client = nullptr)
62       : hybrid_encrypt_set_(std::move(hybrid_encrypt_set)),
63         monitoring_encryption_client_(std::move(monitoring_encryption_client)) {
64   }
65 
66   crypto::tink::util::StatusOr<std::string> Encrypt(
67       absl::string_view plaintext,
68       absl::string_view context_info) const override;
69 
70   ~HybridEncryptSetWrapper() override = default;
71 
72  private:
73   std::unique_ptr<PrimitiveSet<HybridEncrypt>> hybrid_encrypt_set_;
74   std::unique_ptr<MonitoringClient> monitoring_encryption_client_;
75 };
76 
Encrypt(absl::string_view plaintext,absl::string_view context_info) const77 util::StatusOr<std::string> HybridEncryptSetWrapper::Encrypt(
78     absl::string_view plaintext, absl::string_view context_info) const {
79   // BoringSSL expects a non-null pointer for plaintext and context_info,
80   // regardless of whether the size is 0.
81   plaintext = internal::EnsureStringNonNull(plaintext);
82   context_info = internal::EnsureStringNonNull(context_info);
83 
84   auto primary = hybrid_encrypt_set_->get_primary();
85   auto encrypt_result =
86       primary->get_primitive().Encrypt(plaintext, context_info);
87   if (!encrypt_result.ok()) {
88     if (monitoring_encryption_client_ != nullptr) {
89       monitoring_encryption_client_->LogFailure();
90     }
91     return encrypt_result.status();
92   }
93   if (monitoring_encryption_client_ != nullptr) {
94     monitoring_encryption_client_->Log(
95         hybrid_encrypt_set_->get_primary()->get_key_id(), plaintext.size());
96   }
97   const std::string& key_id = primary->get_identifier();
98   return key_id + encrypt_result.value();
99 }
100 
101 }  // anonymous namespace
102 
Wrap(std::unique_ptr<PrimitiveSet<HybridEncrypt>> primitive_set) const103 util::StatusOr<std::unique_ptr<HybridEncrypt>> HybridEncryptWrapper::Wrap(
104     std::unique_ptr<PrimitiveSet<HybridEncrypt>> primitive_set) const {
105   util::Status status = Validate(primitive_set.get());
106   if (!status.ok()) return status;
107 
108   MonitoringClientFactory* const monitoring_factory =
109       internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory();
110 
111   // Monitoring is not enabled. Create a wrapper without monitoring clients.
112   if (monitoring_factory == nullptr) {
113     return {
114         absl::make_unique<HybridEncryptSetWrapper>(std::move(primitive_set))};
115   }
116 
117   util::StatusOr<MonitoringKeySetInfo> keyset_info =
118       internal::MonitoringKeySetInfoFromPrimitiveSet(*primitive_set);
119   if (!keyset_info.ok()) {
120     return keyset_info.status();
121   }
122 
123   util::StatusOr<std::unique_ptr<MonitoringClient>>
124       monitoring_encryption_client = monitoring_factory->New(
125           MonitoringContext(kPrimitive, kEncryptApi, *keyset_info));
126   if (!monitoring_encryption_client.ok()) {
127     return monitoring_encryption_client.status();
128   }
129 
130   return {absl::make_unique<HybridEncryptSetWrapper>(
131       std::move(primitive_set), *std::move(monitoring_encryption_client))};
132 }
133 
134 }  // namespace tink
135 }  // namespace crypto
136