// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstdint>

#include "net/third_party/quic/core/crypto/crypto_secret_boxer.h"

#include "net/third_party/quic/core/crypto/quic_random.h"
#include "net/third_party/quic/platform/api/quic_logging.h"
#include "net/third_party/quic/platform/api/quic_string.h"
#include "third_party/boringssl/src/include/openssl/aead.h"
#include "third_party/boringssl/src/include/openssl/err.h"

namespace quic {

// kSIVNonceSize contains the number of bytes of nonce in each AES-GCM-SIV box.
// AES-GCM-SIV takes a 12-byte nonce and, since the messages are so small, each
// key is good for more than 2^64 source-address tokens. See table 1 of
// https://eprint.iacr.org/2017/168.pdf
static const size_t kSIVNonceSize = 12;

// AES-GCM-SIV comes in AES-128 and AES-256 flavours. The AES-256 version is
// used here so that the key size matches the 256-bit XSalsa20 keys that we
// used to use.
static const size_t kBoxKeySize = 32;

struct CryptoSecretBoxer::State {
  // ctxs are the initialised AEAD contexts. These objects contain the
  // scheduled AES state for each of the keys.
  std::vector<bssl::UniquePtr<EVP_AEAD_CTX>> ctxs;
};

CryptoSecretBoxer::CryptoSecretBoxer() {}

CryptoSecretBoxer::~CryptoSecretBoxer() {}

// static
size_t CryptoSecretBoxer::GetKeySize() {
  return kBoxKeySize;
}

// kAEAD is the AEAD used for boxing: AES-256-GCM-SIV.
static const EVP_AEAD* (*const kAEAD)() = EVP_aead_aes_256_gcm_siv;

void CryptoSecretBoxer::SetKeys(const std::vector<QuicString>& keys) {
  DCHECK(!keys.empty());
  const EVP_AEAD* const aead = kAEAD();
  std::unique_ptr<State> new_state(new State);

  for (const QuicString& key : keys) {
    DCHECK_EQ(kBoxKeySize, key.size());
    bssl::UniquePtr<EVP_AEAD_CTX> ctx(
        EVP_AEAD_CTX_new(aead, reinterpret_cast<const uint8_t*>(key.data()),
                         key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH));
    if (!ctx) {
      ERR_clear_error();
      LOG(DFATAL) << "EVP_AEAD_CTX_init failed";
      return;
    }

    new_state->ctxs.push_back(std::move(ctx));
  }

  QuicWriterMutexLock l(&lock_);
  state_ = std::move(new_state);
}

QuicString CryptoSecretBoxer::Box(QuicRandom* rand,
                                  QuicStringPiece plaintext) const {
  // The box is formatted as:
  //   12 bytes of random nonce
  //   n bytes of ciphertext
  //   16 bytes of authenticator
  size_t out_len =
      kSIVNonceSize + plaintext.size() + EVP_AEAD_max_overhead(kAEAD());

  QuicString ret;
  ret.resize(out_len);
  uint8_t* out = reinterpret_cast<uint8_t*>(const_cast<char*>(ret.data()));

  // Write kSIVNonceSize bytes of random nonce to the beginning of the output
  // buffer.
  rand->RandBytes(out, kSIVNonceSize);
  const uint8_t* const nonce = out;
  out += kSIVNonceSize;
  out_len -= kSIVNonceSize;

  size_t bytes_written;
  {
    QuicReaderMutexLock l(&lock_);
    if (!EVP_AEAD_CTX_seal(state_->ctxs[0].get(), out, &bytes_written, out_len,
                           nonce, kSIVNonceSize,
                           reinterpret_cast<const uint8_t*>(plaintext.data()),
                           plaintext.size(), nullptr, 0)) {
      ERR_clear_error();
      LOG(DFATAL) << "EVP_AEAD_CTX_seal failed";
      return "";
    }
  }

  DCHECK_EQ(out_len, bytes_written);
  return ret;
}

bool CryptoSecretBoxer::Unbox(QuicStringPiece in_ciphertext,
                              QuicString* out_storage,
                              QuicStringPiece* out) const {
  if (in_ciphertext.size() < kSIVNonceSize) {
    return false;
  }

  const uint8_t* const nonce =
      reinterpret_cast<const uint8_t*>(in_ciphertext.data());
  const uint8_t* const ciphertext = nonce + kSIVNonceSize;
  const size_t ciphertext_len = in_ciphertext.size() - kSIVNonceSize;

  out_storage->resize(ciphertext_len);

  bool ok = false;
  {
    QuicReaderMutexLock l(&lock_);
    for (const bssl::UniquePtr<EVP_AEAD_CTX>& ctx : state_->ctxs) {
      size_t bytes_written;
      if (EVP_AEAD_CTX_open(ctx.get(),
                            reinterpret_cast<uint8_t*>(
                                const_cast<char*>(out_storage->data())),
                            &bytes_written, ciphertext_len, nonce,
                            kSIVNonceSize, ciphertext, ciphertext_len, nullptr,
                            0)) {
        ok = true;
        *out = QuicStringPiece(out_storage->data(), bytes_written);
        break;
      }

      ERR_clear_error();
    }
  }

  return ok;
}

}  // namespace quic
