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