// 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/subtle/aes_cmac_boringssl.h"

#include <string>

#include "absl/memory/memory.h"
#include "openssl/cmac.h"
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/status.h"

namespace crypto {
namespace tink {
namespace subtle {

// static
util::StatusOr<std::unique_ptr<Mac>> AesCmacBoringSsl::New(util::SecretData key,
                                                           uint32_t tag_size) {
  if (key.size() != kSmallKeySize && key.size() != kBigKeySize) {
    return util::Status(util::error::INVALID_ARGUMENT, "invalid key size");
  }
  if (tag_size > kMaxTagSize) {
    return util::Status(util::error::INVALID_ARGUMENT, "invalid tag size");
  }
  return {absl::WrapUnique(new AesCmacBoringSsl(std::move(key), tag_size))};
}

util::StatusOr<std::string> AesCmacBoringSsl::ComputeMac(
    absl::string_view data) const {
  // BoringSSL expects a non-null pointer for data,
  // regardless of whether the size is 0.
  data = SubtleUtilBoringSSL::EnsureNonNull(data);

  std::string result;
  ResizeStringUninitialized(&result, kMaxTagSize);
  const int res =
      AES_CMAC(reinterpret_cast<uint8_t*>(&result[0]), key_.data(), key_.size(),
               reinterpret_cast<const uint8_t*>(data.data()), data.size());
  if (res == 0) {
    return util::Status(util::error::INTERNAL,
                        "BoringSSL failed to compute CMAC");
  }
  result.resize(tag_size_);
  return result;
}

util::Status AesCmacBoringSsl::VerifyMac(absl::string_view mac,
                                         absl::string_view data) const {
  // BoringSSL expects a non-null pointer for data,
  // regardless of whether the size is 0.
  data = SubtleUtilBoringSSL::EnsureNonNull(data);

  if (mac.size() != tag_size_) {
    return util::Status(util::error::INVALID_ARGUMENT, "incorrect tag size");
  }
  uint8_t buf[kMaxTagSize];
  const int res =
      AES_CMAC(buf, key_.data(), key_.size(),
               reinterpret_cast<const uint8_t*>(data.data()), data.size());
  if (res == 0) {
    return util::Status(util::error::INTERNAL,
                        "BoringSSL failed to compute CMAC");
  }
  uint8_t diff = 0;
  for (uint32_t i = 0; i < tag_size_; i++) {
    diff |= buf[i] ^ static_cast<uint8_t>(mac[i]);
  }
  if (diff != 0) {
    return util::Status(util::error::INVALID_ARGUMENT, "verification failed");
  }
  return util::OkStatus();
}

}  // namespace subtle
}  // namespace tink
}  // namespace crypto
