// Copyright (c) 2012 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 "sync/util/cryptographer.h"

#include <algorithm>

#include "base/base64.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "sync/protocol/nigori_specifics.pb.h"
#include "sync/util/encryptor.h"

namespace syncer {

const char kNigoriTag[] = "google_chrome_nigori";

// We name a particular Nigori instance (ie. a triplet consisting of a hostname,
// a username, and a password) by calling Permute on this string. Since the
// output of Permute is always the same for a given triplet, clients will always
// assign the same name to a particular triplet.
const char kNigoriKeyName[] = "nigori-key";

Cryptographer::Cryptographer(Encryptor* encryptor)
    : encryptor_(encryptor) {
  DCHECK(encryptor);
}

Cryptographer::Cryptographer(const Cryptographer& other)
    : encryptor_(other.encryptor_),
      default_nigori_name_(other.default_nigori_name_) {
  for (NigoriMap::const_iterator it = other.nigoris_.begin();
       it != other.nigoris_.end();
       ++it) {
    std::string user_key, encryption_key, mac_key;
    it->second->ExportKeys(&user_key, &encryption_key, &mac_key);
    linked_ptr<Nigori> nigori_copy(new Nigori());
    nigori_copy->InitByImport(user_key, encryption_key, mac_key);
    nigoris_.insert(std::make_pair(it->first, nigori_copy));
  }

  if (other.pending_keys_) {
    pending_keys_.reset(new sync_pb::EncryptedData(*(other.pending_keys_)));
  }
}

Cryptographer::~Cryptographer() {}


void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) {
  if (is_initialized()) {
    NOTREACHED();
    return;
  }

  std::string serialized_nigori_key =
      UnpackBootstrapToken(restored_bootstrap_token);
  if (serialized_nigori_key.empty())
    return;
  ImportNigoriKey(serialized_nigori_key);
}

bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const {
  return nigoris_.end() != nigoris_.find(data.key_name());
}

bool Cryptographer::CanDecryptUsingDefaultKey(
    const sync_pb::EncryptedData& data) const {
  return !default_nigori_name_.empty() &&
         data.key_name() == default_nigori_name_;
}

bool Cryptographer::Encrypt(
    const ::google::protobuf::MessageLite& message,
    sync_pb::EncryptedData* encrypted) const {
  DCHECK(encrypted);
  if (default_nigori_name_.empty()) {
    LOG(ERROR) << "Cryptographer not ready, failed to encrypt.";
    return false;
  }

  std::string serialized;
  if (!message.SerializeToString(&serialized)) {
    LOG(ERROR) << "Message is invalid/missing a required field.";
    return false;
  }

  return EncryptString(serialized, encrypted);
}

bool Cryptographer::EncryptString(
    const std::string& serialized,
    sync_pb::EncryptedData* encrypted) const {
  if (CanDecryptUsingDefaultKey(*encrypted)) {
    const std::string& original_serialized = DecryptToString(*encrypted);
    if (original_serialized == serialized) {
      DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches.";
      return true;
    }
  }

  NigoriMap::const_iterator default_nigori =
      nigoris_.find(default_nigori_name_);
  if (default_nigori == nigoris_.end()) {
    LOG(ERROR) << "Corrupt default key.";
    return false;
  }

  encrypted->set_key_name(default_nigori_name_);
  if (!default_nigori->second->Encrypt(serialized,
                                       encrypted->mutable_blob())) {
    LOG(ERROR) << "Failed to encrypt data.";
    return false;
  }
  return true;
}

bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted,
                            ::google::protobuf::MessageLite* message) const {
  DCHECK(message);
  std::string plaintext = DecryptToString(encrypted);
  return message->ParseFromString(plaintext);
}

std::string Cryptographer::DecryptToString(
    const sync_pb::EncryptedData& encrypted) const {
  NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name());
  if (nigoris_.end() == it) {
    NOTREACHED() << "Cannot decrypt message";
    return std::string();  // Caller should have called CanDecrypt(encrypt).
  }

  std::string plaintext;
  if (!it->second->Decrypt(encrypted.blob(), &plaintext)) {
    return std::string();
  }

  return plaintext;
}

bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
  DCHECK(encrypted);
  DCHECK(!nigoris_.empty());

  // Create a bag of all the Nigori parameters we know about.
  sync_pb::NigoriKeyBag bag;
  for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end();
       ++it) {
    const Nigori& nigori = *it->second;
    sync_pb::NigoriKey* key = bag.add_key();
    key->set_name(it->first);
    nigori.ExportKeys(key->mutable_user_key(),
                      key->mutable_encryption_key(),
                      key->mutable_mac_key());
  }

  // Encrypt the bag with the default Nigori.
  return Encrypt(bag, encrypted);
}

bool Cryptographer::AddKey(const KeyParams& params) {
  // Create the new Nigori and make it the default encryptor.
  scoped_ptr<Nigori> nigori(new Nigori);
  if (!nigori->InitByDerivation(params.hostname,
                                params.username,
                                params.password)) {
    NOTREACHED();  // Invalid username or password.
    return false;
  }
  return AddKeyImpl(nigori.Pass(), true);
}

bool Cryptographer::AddNonDefaultKey(const KeyParams& params) {
  DCHECK(is_initialized());
  // Create the new Nigori and add it to the keybag.
  scoped_ptr<Nigori> nigori(new Nigori);
  if (!nigori->InitByDerivation(params.hostname,
                                params.username,
                                params.password)) {
    NOTREACHED();  // Invalid username or password.
    return false;
  }
  return AddKeyImpl(nigori.Pass(), false);
}

bool Cryptographer::AddKeyFromBootstrapToken(
    const std::string restored_bootstrap_token) {
  // Create the new Nigori and make it the default encryptor.
  std::string serialized_nigori_key = UnpackBootstrapToken(
      restored_bootstrap_token);
  return ImportNigoriKey(serialized_nigori_key);
}

bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori,
                               bool set_as_default) {
  std::string name;
  if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) {
    NOTREACHED();
    return false;
  }

  nigoris_[name] = make_linked_ptr(initialized_nigori.release());

  // Check if the key we just added can decrypt the pending keys and add them
  // too if so.
  if (pending_keys_.get() && CanDecrypt(*pending_keys_)) {
    sync_pb::NigoriKeyBag pending_bag;
    Decrypt(*pending_keys_, &pending_bag);
    InstallKeyBag(pending_bag);
    SetDefaultKey(pending_keys_->key_name());
    pending_keys_.reset();
  }

  // The just-added key takes priority over the pending keys as default.
  if (set_as_default) SetDefaultKey(name);
  return true;
}

void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) {
  DCHECK(CanDecrypt(encrypted));

  sync_pb::NigoriKeyBag bag;
  if (!Decrypt(encrypted, &bag))
    return;
  InstallKeyBag(bag);
}

void Cryptographer::SetDefaultKey(const std::string& key_name) {
  DCHECK(nigoris_.end() != nigoris_.find(key_name));
  default_nigori_name_ = key_name;
}

void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) {
  DCHECK(!CanDecrypt(encrypted));
  DCHECK(!encrypted.blob().empty());
  pending_keys_.reset(new sync_pb::EncryptedData(encrypted));
}

const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const {
  DCHECK(has_pending_keys());
  return *(pending_keys_.get());
}

bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
  Nigori nigori;
  if (!nigori.InitByDerivation(params.hostname,
                               params.username,
                               params.password)) {
    NOTREACHED();
    return false;
  }

  std::string plaintext;
  if (!nigori.Decrypt(pending_keys_->blob(), &plaintext))
    return false;

  sync_pb::NigoriKeyBag bag;
  if (!bag.ParseFromString(plaintext)) {
    NOTREACHED();
    return false;
  }
  InstallKeyBag(bag);
  const std::string& new_default_key_name = pending_keys_->key_name();
  SetDefaultKey(new_default_key_name);
  pending_keys_.reset();
  return true;
}

bool Cryptographer::GetBootstrapToken(std::string* token) const {
  DCHECK(token);
  std::string unencrypted_token = GetDefaultNigoriKeyData();
  if (unencrypted_token.empty())
    return false;

  std::string encrypted_token;
  if (!encryptor_->EncryptString(unencrypted_token, &encrypted_token)) {
    NOTREACHED();
    return false;
  }

  base::Base64Encode(encrypted_token, token);

  return true;
}

std::string Cryptographer::UnpackBootstrapToken(
    const std::string& token) const {
  if (token.empty())
    return std::string();

  std::string encrypted_data;
  if (!base::Base64Decode(token, &encrypted_data)) {
    DLOG(WARNING) << "Could not decode token.";
    return std::string();
  }

  std::string unencrypted_token;
  if (!encryptor_->DecryptString(encrypted_data, &unencrypted_token)) {
    DLOG(WARNING) << "Decryption of bootstrap token failed.";
    return std::string();
  }
  return unencrypted_token;
}

void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) {
  int key_size = bag.key_size();
  for (int i = 0; i < key_size; ++i) {
    const sync_pb::NigoriKey key = bag.key(i);
    // Only use this key if we don't already know about it.
    if (nigoris_.end() == nigoris_.find(key.name())) {
      scoped_ptr<Nigori> new_nigori(new Nigori);
      if (!new_nigori->InitByImport(key.user_key(),
                                    key.encryption_key(),
                                    key.mac_key())) {
        NOTREACHED();
        continue;
      }
      nigoris_[key.name()] = make_linked_ptr(new_nigori.release());
    }
  }
}

bool Cryptographer::KeybagIsStale(
    const sync_pb::EncryptedData& encrypted_bag) const {
  if (!is_ready())
    return false;
  if (encrypted_bag.blob().empty())
    return true;
  if (!CanDecrypt(encrypted_bag))
    return false;
  if (!CanDecryptUsingDefaultKey(encrypted_bag))
    return true;
  sync_pb::NigoriKeyBag bag;
  if (!Decrypt(encrypted_bag, &bag)) {
    LOG(ERROR) << "Failed to decrypt keybag for stale check. "
               << "Assuming keybag is corrupted.";
    return true;
  }
  if (static_cast<size_t>(bag.key_size()) < nigoris_.size())
    return true;
  return false;
}

std::string Cryptographer::GetDefaultNigoriKeyName() const {
  return default_nigori_name_;
}

std::string Cryptographer::GetDefaultNigoriKeyData() const {
  if (!is_initialized())
    return std::string();
  NigoriMap::const_iterator iter = nigoris_.find(default_nigori_name_);
  if (iter == nigoris_.end())
    return std::string();
  sync_pb::NigoriKey key;
  if (!iter->second->ExportKeys(key.mutable_user_key(),
                                key.mutable_encryption_key(),
                                key.mutable_mac_key()))
    return std::string();
  return key.SerializeAsString();
}

bool Cryptographer::ImportNigoriKey(const std::string serialized_nigori_key) {
  if (serialized_nigori_key.empty())
    return false;

  sync_pb::NigoriKey key;
  if (!key.ParseFromString(serialized_nigori_key))
    return false;

  scoped_ptr<Nigori> nigori(new Nigori);
  if (!nigori->InitByImport(key.user_key(), key.encryption_key(),
                            key.mac_key())) {
    NOTREACHED();
    return false;
  }

  if (!AddKeyImpl(nigori.Pass(), true))
    return false;
  return true;
}

}  // namespace syncer
