// 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/streamingaead/aes_gcm_hkdf_streaming_key_manager.h"

#include "tink/subtle/aes_gcm_hkdf_stream_segment_encrypter.h"
#include "tink/subtle/random.h"
#include "tink/util/validation.h"

namespace crypto {
namespace tink {

using ::crypto::tink::subtle::AesGcmHkdfStreamSegmentEncrypter;
using ::crypto::tink::util::Status;
using ::crypto::tink::util::StatusOr;
using ::google::crypto::tink::AesGcmHkdfStreamingKey;
using ::google::crypto::tink::AesGcmHkdfStreamingKeyFormat;
using ::google::crypto::tink::AesGcmHkdfStreamingParams;
using ::google::crypto::tink::HashType;
using ::google::crypto::tink::KeyData;

namespace {

Status ValidateParams(const AesGcmHkdfStreamingParams& params) {
  if (!(params.hkdf_hash_type() == HashType::SHA1 ||
        params.hkdf_hash_type() == HashType::SHA256 ||
        params.hkdf_hash_type() == HashType::SHA512)) {
    return Status(util::error::INVALID_ARGUMENT, "unsupported hkdf_hash_type");
  }
  int header_size = 1 + params.derived_key_size() +
      AesGcmHkdfStreamSegmentEncrypter::kNoncePrefixSizeInBytes;
  if (params.ciphertext_segment_size() <=
      header_size + AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes) {
    return Status(util::error::INVALID_ARGUMENT,
                  "ciphertext_segment_size too small");
  }
  return ValidateAesKeySize(params.derived_key_size());
}

}  // namespace

crypto::tink::util::StatusOr<google::crypto::tink::AesGcmHkdfStreamingKey>
AesGcmHkdfStreamingKeyManager::CreateKey(
    const google::crypto::tink::AesGcmHkdfStreamingKeyFormat& key_format)
    const {
  AesGcmHkdfStreamingKey key;
  key.set_version(get_version());
  key.set_key_value(subtle::Random::GetRandomBytes(key_format.key_size()));
  *key.mutable_params() = key_format.params();
  return key;
};


Status AesGcmHkdfStreamingKeyManager::ValidateKey(
    const AesGcmHkdfStreamingKey& key) const {
  Status status = ValidateVersion(key.version(), get_version());
  if (!status.ok()) return status;
  if (key.key_value().size() < key.params().derived_key_size()) {
    return Status(util::error::INVALID_ARGUMENT,
                  "key_value (i.e. ikm) too short");
  }
  return ValidateParams(key.params());
}

Status AesGcmHkdfStreamingKeyManager::ValidateKeyFormat(
    const AesGcmHkdfStreamingKeyFormat& key_format) const {
  if (key_format.key_size() < key_format.params().derived_key_size()) {
    return Status(util::error::INVALID_ARGUMENT,
                  "key_size must not be smaller than derived_key_size");
  }
  return ValidateParams(key_format.params());
}

}  // namespace tink
}  // namespace crypto
