diff options
author | tholenst <tholenst@google.com> | 2018-10-25 06:41:23 -0700 |
---|---|---|
committer | Charles Lee <ckl@google.com> | 2018-10-25 11:16:24 -0700 |
commit | 0fa8ee7a3906b6afa8370e94d0679aadfca3e1dd (patch) | |
tree | 29f57a382edf6fe637ed92b19b16fb3a771880cb /cc/mac/mac_wrapper.cc | |
parent | 229fbd520e30ae46b53b248ef9bfca35ab121801 (diff) | |
download | tink-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.cc | 138 |
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 |