// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 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 "registry_key.h"
#include "registry_key_impl_lsa.h"
#include "registry_data_impl_lsa_poleklist.h"
#include <mobius/crypt/cipher_rc4.h>
#include <mobius/crypt/hash_md5.h>
#include <mobius/decoder/data_decoder.h>

namespace mobius
{
namespace forensics
{
namespace registry
{
namespace               // local namespace
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get registry SYSKEY
//! \see https://github.com/Neohapsis/creddump7/blob/master/framework/win32/lsasecrets.py
//! \param root root registry key
//! \return syskey
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static const mobius::bytearray
get_syskey (registry_key root)
{
  mobius::bytearray syskey;

  auto lsa_key = root.get_key_by_path ("\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa");

  if (lsa_key)
    {
      auto jd_key = lsa_key.get_key_by_name ("JD");
      auto skew1_key = lsa_key.get_key_by_name ("Skew1");
      auto gbg_key = lsa_key.get_key_by_name ("GBG");
      auto data_key = lsa_key.get_key_by_name ("Data");

      if (jd_key && skew1_key && gbg_key && data_key)
        {
          mobius::bytearray tmp;
          tmp.from_hexstring (jd_key.get_classname () + skew1_key.get_classname () + gbg_key.get_classname () + data_key.get_classname ());
          syskey = mobius::bytearray ({tmp[8], tmp[5], tmp[4], tmp[2], tmp[11], tmp[9], tmp[13], tmp[3], tmp[0], tmp[6], tmp[1], tmp[12], tmp[14], tmp[10], tmp[15], tmp[7]});
        }
    }

  return syskey;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get decrypted LSAKEY
//! \param syskey registry SysKey
//! \param data PolSecKey value's data
//! \return decrypted LSAKEY
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static const mobius::bytearray
get_lsa_key_from_polseckey (
  const mobius::bytearray& syskey,
  const mobius::bytearray& data)
{
  mobius::crypt::hash_md5 md5;
  md5.update (syskey);

  auto salt = data.slice (60, 75);
  for (int i = 0; i < 1000; i++)
    md5.update (salt);

  mobius::crypt::cipher_rc4 rc4 (md5.get_digest ());
  auto rc4_key = data.slice (12, 59);

  return rc4.decrypt (rc4_key).slice (16, 31);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief get decrypted LSAKEY
//! \param syskey registry SysKey
//! \param data PolEKList value's data
//! \return decrypted LSAKEY
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static const mobius::bytearray
get_lsa_key_from_poleklist (
  const mobius::bytearray& syskey,
  const mobius::bytearray& data)
{
  mobius::bytearray lsa_key;

  auto poleklist = decrypt_aes (syskey, data);

  if (poleklist)
    {
      auto decoder = mobius::decoder::data_decoder (poleklist);
      decoder.skip (64);
      auto size = decoder.get_uint32_le ();
      lsa_key = decoder.get_bytearray_by_size (size);
    }

  return lsa_key;
}

} // local namespace

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief set LSA Secrets keys
//! \see https://www.passcape.com/index.php?section=docsys&cmd=details&id=23
//! \see http://moyix.blogspot.com.br/2008/02/decrypting-lsa-secrets.html
//! \see https://github.com/Neohapsis/creddump7/blob/master/framework/win32/lsasecrets.py
//! \param root registry root key
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
registry_set_lsa_keys (registry_key root)
{
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // try to recover syskey
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  auto syskey = get_syskey (root);

  if (!syskey)
    return;

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // decrypt LSA key
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  mobius::bytearray lsa_key;
  registry_key_impl_lsa::type type;

  // Win2k - WinXp
  auto polseckey_data = root.get_data_by_path ("\\HKEY_LOCAL_MACHINE\\SECURITY\\Policy\\PolSecretEncryptionKey\\(default)");

  // Vista and newer ones
  auto poleklist_data = root.get_data_by_path ("\\HKEY_LOCAL_MACHINE\\SECURITY\\Policy\\PolEKList\\(default)");

  if (polseckey_data)
    {
      lsa_key = get_lsa_key_from_polseckey (syskey, polseckey_data.get_data ());
      type = registry_key_impl_lsa::type::polseckey;
    }

  else if (poleklist_data)
    {
      lsa_key = get_lsa_key_from_poleklist (syskey, poleklist_data.get_data ());
      type = registry_key_impl_lsa::type::poleklist;
    }

  if (!lsa_key)
    return;

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // set LSA Secrets keys
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  for (auto key : root.get_key_by_mask ("\\HKEY_LOCAL_MACHINE\\SECURITY\\Policy\\Secrets\\*"))
    {
      auto currval_key = key.get_key_by_name ("Currval");

      if (currval_key)
        key.add_key (registry_key (std::make_shared <registry_key_impl_lsa> (currval_key, lsa_key, type)));

      auto oldval_key = key.get_key_by_name ("Oldval");

      if (oldval_key)
        key.add_key (registry_key (std::make_shared <registry_key_impl_lsa> (oldval_key, lsa_key, type)));
    }
}

} // namespace registry
} // namespace forensics
} // namespace mobius
