aboutsummaryrefslogtreecommitdiff
path: root/cc/mac/mac_wrapper.cc
diff options
context:
space:
mode:
authortholenst <tholenst@google.com>2018-10-25 06:41:23 -0700
committerCharles Lee <ckl@google.com>2018-10-25 11:16:24 -0700
commit0fa8ee7a3906b6afa8370e94d0679aadfca3e1dd (patch)
tree29f57a382edf6fe637ed92b19b16fb3a771880cb /cc/mac/mac_wrapper.cc
parent229fbd520e30ae46b53b248ef9bfca35ab121801 (diff)
downloadtink-0fa8ee7a3906b6afa8370e94d0679aadfca3e1dd.tar.gz
Change the MacSetWrapper to a MacWrapper and register it.
PiperOrigin-RevId: 218677409 GitOrigin-RevId: 61735fcdf8fb20ebf0272b2e4602350c56b4e3ee
Diffstat (limited to 'cc/mac/mac_wrapper.cc')
-rw-r--r--cc/mac/mac_wrapper.cc138
1 files changed, 138 insertions, 0 deletions
diff --git a/cc/mac/mac_wrapper.cc b/cc/mac/mac_wrapper.cc
new file mode 100644
index 000000000..f5948178f
--- /dev/null
+++ b/cc/mac/mac_wrapper.cc
@@ -0,0 +1,138 @@
+// Copyright 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tink/mac/mac_wrapper.h"
+
+#include "tink/crypto_format.h"
+#include "tink/mac.h"
+#include "tink/primitive_set.h"
+#include "tink/subtle/subtle_util_boringssl.h"
+#include "tink/util/status.h"
+#include "tink/util/statusor.h"
+#include "proto/tink.pb.h"
+
+namespace crypto {
+namespace tink {
+
+using google::crypto::tink::OutputPrefixType;
+
+namespace {
+
+class MacSetWrapper : public Mac {
+ public:
+ explicit MacSetWrapper(std::unique_ptr<PrimitiveSet<Mac>> mac_set)
+ : mac_set_(std::move(mac_set)) {}
+
+ crypto::tink::util::StatusOr<std::string> ComputeMac(
+ absl::string_view data) const override;
+
+ crypto::tink::util::Status VerifyMac(absl::string_view mac_value,
+ absl::string_view data) const override;
+
+ ~MacSetWrapper() override {}
+
+ private:
+ std::unique_ptr<PrimitiveSet<Mac>> mac_set_;
+};
+
+util::Status Validate(PrimitiveSet<Mac>* mac_set) {
+ if (mac_set == nullptr) {
+ return util::Status(util::error::INTERNAL, "mac_set must be non-NULL");
+ }
+ if (mac_set->get_primary() == nullptr) {
+ return util::Status(util::error::INVALID_ARGUMENT,
+ "mac_set has no primary");
+ }
+ return util::Status::OK;
+}
+
+util::StatusOr<std::string> MacSetWrapper::ComputeMac(
+ absl::string_view data) const {
+ // BoringSSL expects a non-null pointer for data,
+ // regardless of whether the size is 0.
+ data = subtle::SubtleUtilBoringSSL::EnsureNonNull(data);
+
+ auto primary = mac_set_->get_primary();
+ std::string local_data;
+ if (primary->get_output_prefix_type() == OutputPrefixType::LEGACY) {
+ local_data = std::string(data);
+ local_data.append(
+ reinterpret_cast<const char*>(&CryptoFormat::kLegacyStartByte), 1);
+ data = local_data;
+ }
+ auto compute_mac_result = primary->get_primitive().ComputeMac(data);
+ if (!compute_mac_result.ok()) return compute_mac_result.status();
+ const std::string& key_id = primary->get_identifier();
+ return key_id + compute_mac_result.ValueOrDie();
+}
+
+util::Status MacSetWrapper::VerifyMac(
+ absl::string_view mac_value,
+ absl::string_view data) const {
+ data = subtle::SubtleUtilBoringSSL::EnsureNonNull(data);
+ mac_value = subtle::SubtleUtilBoringSSL::EnsureNonNull(mac_value);
+
+ if (mac_value.length() > CryptoFormat::kNonRawPrefixSize) {
+ const std::string& key_id = std::string(mac_value.substr(0,
+ CryptoFormat::kNonRawPrefixSize));
+ auto primitives_result = mac_set_->get_primitives(key_id);
+ if (primitives_result.ok()) {
+ absl::string_view raw_mac_value =
+ mac_value.substr(CryptoFormat::kNonRawPrefixSize);
+ std::string local_data;
+ for (auto& mac_entry : *(primitives_result.ValueOrDie())) {
+ if (mac_entry->get_output_prefix_type() == OutputPrefixType::LEGACY) {
+ local_data = std::string(data);
+ local_data.append(1, CryptoFormat::kLegacyStartByte);
+ data = local_data;
+ }
+ Mac& mac = mac_entry->get_primitive();
+ util::Status status = mac.VerifyMac(raw_mac_value, data);
+ if (status.ok()) {
+ return status;
+ } else {
+ // TODO(przydatek): LOG that a matching key didn't verify the MAC.
+ }
+ }
+ }
+ }
+
+ // No matching key succeeded with verification, try all RAW keys.
+ auto raw_primitives_result = mac_set_->get_raw_primitives();
+ if (raw_primitives_result.ok()) {
+ for (auto& mac_entry : *(raw_primitives_result.ValueOrDie())) {
+ Mac& mac = mac_entry->get_primitive();
+ util::Status status = mac.VerifyMac(mac_value, data);
+ if (status.ok()) {
+ return status;
+ }
+ }
+ }
+ return util::Status(util::error::INVALID_ARGUMENT, "verification failed");
+}
+
+} // namespace
+
+util::StatusOr<std::unique_ptr<Mac>> MacWrapper::Wrap(
+ std::unique_ptr<PrimitiveSet<Mac>> mac_set) const {
+ util::Status status = Validate(mac_set.get());
+ if (!status.ok()) return status;
+ std::unique_ptr<Mac> mac(new MacSetWrapper(std::move(mac_set)));
+ return std::move(mac);
+}
+
+} // namespace tink
+} // namespace crypto