// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CRYPTO_HMAC_H_
#define CRYPTO_HMAC_H_

#include <stddef.h>

#include <array>
#include <memory>
#include <string_view>
#include <vector>

#include "base/check.h"
#include "base/containers/span.h"
#include "crypto/crypto_export.h"
#include "crypto/hash.h"
#include "crypto/secure_util.h"
#include "third_party/boringssl/src/include/openssl/hmac.h"

namespace crypto {

namespace hmac {

// Single-shot interfaces for working with HMACs. Unless your code needs to be
// generic over hash kinds, you should use the convenience interfaces that are
// named after a specific kind, since they allow compile-time error checking of
// the hmac size.
// Deprecated: don't use SHA-1. Consult a CRYPTO_OWNERS member before adding
// new uses. See https://crbug.com/527094641.
CRYPTO_EXPORT std::array<uint8_t, crypto::hash::kSha1Size> SignSha1(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data);

CRYPTO_EXPORT std::array<uint8_t, crypto::hash::kSha256Size> SignSha256(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data);

CRYPTO_EXPORT std::array<uint8_t, crypto::hash::kSha512Size> SignSha512(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data);

// Deprecated: don't use SHA-1. Consult a CRYPTO_OWNERS member before adding
// new uses. See https://crbug.com/527094641.
[[nodiscard]] CRYPTO_EXPORT bool VerifySha1(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data,
    base::span<const uint8_t, crypto::hash::kSha1Size> hmac);

[[nodiscard]] CRYPTO_EXPORT bool VerifySha256(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data,
    base::span<const uint8_t, crypto::hash::kSha256Size> hmac);

[[nodiscard]] CRYPTO_EXPORT bool VerifySha512(
    base::span<const uint8_t> key,
    base::span<const uint8_t> data,
    base::span<const uint8_t, crypto::hash::kSha512Size> hmac);

// If you need to be generic over hash types, you can instead use these, but you
// must pass the correct size buffer for |hmac|:
CRYPTO_EXPORT void Sign(crypto::hash::HashKind kind,
                        base::span<const uint8_t> key,
                        base::span<const uint8_t> data,
                        base::span<uint8_t> hmac);
[[nodiscard]] CRYPTO_EXPORT bool Verify(crypto::hash::HashKind kind,
                                        base::span<const uint8_t> key,
                                        base::span<const uint8_t> data,
                                        base::span<const uint8_t> hmac);

// Streaming sign and verify interfaces. In general you should only use these if
// you are taking the HMAC of multiple chunks of data and want to avoid making
// an intermediate copy - otherwise the one-shot interfaces are simpler to use.
//
// These classes don't impose any requirements on key sizes.
//
// After you call Finish() on an instance of these classes, it is illegal to
// call Update() or Finish() on it again.
class CRYPTO_EXPORT HmacSigner {
 public:
  HmacSigner(crypto::hash::HashKind kind, base::span<const uint8_t> key);
  ~HmacSigner();

  void Update(base::span<const uint8_t> data);
  void Finish(base::span<uint8_t> result);
  std::vector<uint8_t> Finish();

 private:
  const crypto::hash::HashKind kind_;
  bool finished_;
  bssl::ScopedHMAC_CTX ctx_;
};

class CRYPTO_EXPORT HmacVerifier {
 public:
  HmacVerifier(crypto::hash::HashKind kind, base::span<const uint8_t> key);
  ~HmacVerifier();

  void Update(base::span<const uint8_t> data);

  // Returns whether the signature of all the data passed in via Update() so far
  // matches |expected_signature|. This function tolerates the expected
  // signature being the wrong length (by returning false in that case).
  [[nodiscard]] bool Finish(base::span<const uint8_t> expected_signature);

 private:
  HmacSigner signer_;
};

}  // namespace hmac

}  // namespace crypto

#endif  // CRYPTO_HMAC_H_
