// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022 Eduardo Aguiar
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "cipher.h"
#include "cipher_3des.h"
#include "cipher_aes.h"
#include "cipher_blowfish.h"
#include "cipher_des.h"
#include "cipher_rc2.h"
#include "cipher_rc4.h"
#include "cipher_rot13.h"
#include "cipher_zip.h"
#include <mobius/exception.inc>
#include <stdexcept>

namespace mobius
{
namespace crypt
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Assign from another cipher
//! \param h cipher object
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
cipher::_assign (const cipher& h)
{
  cipher_id_ = h.cipher_id_;

  if (cipher_id_ == "3des")
    pimpl_ = std::make_unique <cipher_3des> (static_cast <cipher_3des&> (*h.pimpl_));

  else if (cipher_id_ == "aes")
    pimpl_ = std::make_unique <cipher_aes> (static_cast <cipher_aes&> (*h.pimpl_));

  else if (cipher_id_ == "blowfish")
    pimpl_ = std::make_unique <cipher_blowfish> (static_cast <cipher_blowfish&> (*h.pimpl_));

  else if (cipher_id_ == "des")
    pimpl_ = std::make_unique <cipher_des> (static_cast <cipher_des&> (*h.pimpl_));

  else if (cipher_id_ == "rc2")
    pimpl_ = std::make_unique <cipher_rc2> (static_cast <cipher_rc2&> (*h.pimpl_));

  else if (cipher_id_ == "rc4")
    pimpl_ = std::make_unique <cipher_rc4> (static_cast <cipher_rc4&> (*h.pimpl_));

  else if (cipher_id_ == "rot13")
    pimpl_ = std::make_unique <cipher_rot13> (static_cast <cipher_rot13&> (*h.pimpl_));

  else if (cipher_id_ == "zip")
    pimpl_ = std::make_unique <cipher_zip> (static_cast <cipher_zip&> (*h.pimpl_));

  else
    throw std::invalid_argument (MOBIUS_EXCEPTION_MSG ("Invalid cipher ID"));
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Initialize object
//! \param cipher_id cipher class ID (md5, sha1, ...)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
cipher::cipher (
  const std::string& cipher_id,
  const mobius::bytearray& key,
  const std::string& block_mode,
  const mobius::bytearray& iv
)
  : cipher_id_ (cipher_id)
{
  if (cipher_id_ == "3des")
    pimpl_ = std::make_unique <cipher_3des> (key, block_mode, iv);

  else if (cipher_id_ == "aes")
    pimpl_ = std::make_unique <cipher_aes> (key, block_mode, iv);

  else if (cipher_id_ == "blowfish")
    pimpl_ = std::make_unique <cipher_blowfish> (key, block_mode, iv);

  else if (cipher_id_ == "des")
    pimpl_ = std::make_unique <cipher_des> (key, block_mode, iv);

  else if (cipher_id_ == "rc2")
    pimpl_ = std::make_unique <cipher_rc2> (key, block_mode, iv);

  else if (cipher_id_ == "rc4")
    pimpl_ = std::make_unique <cipher_rc4> (key);

  else if (cipher_id_ == "rot13")
    pimpl_ = std::make_unique <cipher_rot13> ();

  else if (cipher_id_ == "zip")
    pimpl_ = std::make_unique <cipher_zip> (key);

  else
    throw std::invalid_argument (MOBIUS_EXCEPTION_MSG ("Invalid cipher ID"));
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Copy constructor
//! \param cipher_id cipher class ID (aes, blowfish, ...)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
cipher::cipher (const cipher& h)
{
  _assign (h);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Copy constructor
//! \param cipher_id cipher class ID (aes, blowfish, ...)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
cipher&
cipher::operator= (const cipher& h)
{
  _assign (h);

  return *this;
}

} // namespace crypt
} // namespace mobius
