/*****************************************************************************\
*                                                                             *
*  Name   : key_generator                                                     *
*  Author : Chris Koeritz                                                     *
*                                                                             *
*******************************************************************************
* Copyright (c) 2002-$now By Author.  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 of   *
* the License or (at your option) any later version.  This is online at:      *
*     http://www.fsf.org/copyleft/gpl.html                                    *
* Please send any updates to: fred@gruntose.com                               *
\*****************************************************************************/

#include "ice_key.h"
#include "key_generator.h"

#include <basis/byte_array.h>
#include <basis/log_base.h>

#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)

// define these for later reference:
extern byte key_part_0[8], key_part_1[8], key_part_2[8], key_part_3[8],
    key_part_4[8], key_part_5[8], key_part_6[8], key_part_7[8],
    key_part_8[8], key_part_9[8], key_part_10[8], key_part_11[8];

byte key_part_4[8] = { 0xba, 0x4d, 0xf6, 0x27, 0xf8, 0xed, 0xc6, 0x3e };
byte key_part_10[8] = { 0x12, 0xea, 0x7b, 0x96, 0x17, 0x32, 0x6f, 0x20 };

key_generator::key_generator(int key_size)
: _key_size(key_size)
{
}

byte key_part_5[8] = { 0xaf, 0xeb, 0x74, 0xc3, 0xe8, 0xde, 0xba, 0xcd };
byte key_part_9[8] = { 0x3c, 0x26, 0xab, 0xdd, 0xbe, 0x41, 0xed, 0x1c };

key_generator::~key_generator()
{
}

byte key_part_1[8] = { 0x34, 0x98, 0xdb, 0xed, 0x32, 0x19, 0x82, 0xf0 };
byte key_part_6[8] = { 0xa2, 0x85, 0x49, 0x8a, 0xf4, 0xbe, 0xee, 0x17 };

void key_generator::fill_default_key(byte_array &to_fill)
{
  to_fill.reset(_key_size);
  for (int i = 0; i < _key_size; i += 8) {
    byte *chosen_bit = NIL;
    switch (i % 12) {
      // we wrap around if they have a key bigger than our default.
      case 0: chosen_bit = key_part_0; break;
      case 1: chosen_bit = key_part_1; break;
      case 2: chosen_bit = key_part_2; break;
      case 3: chosen_bit = key_part_3; break;
      case 4: chosen_bit = key_part_4; break;
      case 5: chosen_bit = key_part_5; break;
      case 6: chosen_bit = key_part_6; break;
      case 7: chosen_bit = key_part_7; break;
      case 8: chosen_bit = key_part_8; break;
      case 9: chosen_bit = key_part_9; break;
      case 10: chosen_bit = key_part_10; break;
      case 11: chosen_bit = key_part_11; break;
      default: chosen_bit = key_part_0; break;  // should never happen.
    }
    for (int j = 0; j < 8; j++) {
      if (i + j >= _key_size) break;  // skip if we've passed end.
      to_fill[i + j] = chosen_bit[j];
    }
  }
}

byte key_part_2[8] = { 0x76, 0x54, 0x9b, 0x23, 0x6f, 0x95, 0x12, 0x03 };
byte key_part_7[8] = { 0x11, 0x90, 0x92, 0xb0, 0xcb, 0x2a, 0xa4, 0x1a };
byte key_part_0[8] = { 0xed, 0x6b, 0xb4, 0xdd, 0x1f, 0x48, 0x64, 0x19 };

bool key_generator::twist_key(int stage, const byte_array &previous_key,
    const byte_array &fodder, byte_array &new_key)
{
  FUNCDEF("twist_key");
  byte_array prior_key = previous_key;  // make it non-const.
  if (!stage && !prior_key.length()) {
    fill_default_key(prior_key);
  } else if (prior_key.length() != _key_size) {
    LOG("erroneous key size passed in.");
    return false;
  }

  ice_key temp_key(prior_key.length() / 8);
  temp_key.set(prior_key);
  byte_array real_fodder;
  if (!temp_key.decrypt(fodder, real_fodder)) {
    LOG("failure to decrypt fodder chunk.");
    return false;
  }

  new_key = prior_key;

  int starting_point = (stage * real_fodder[0] + real_fodder[1]) % _key_size;
    // we pick a starting point based on the stage and first fodder bytes.
  // the loop iterates over the new fodder bytes and munges them into the
  // current key to make a new key.  if the fodder isn't long enough, it
  // might not transform all of the key bytes.
  for (int i = 0; i < real_fodder.length(); i++) {
    bool add = !!(i % 2);  // if true, add fodder.  if not, XOR fodder.
    int index = (i + starting_point) % _key_size;
    byte new_value = new_key[index];
    if (add) new_value += real_fodder[i];
    else new_value ^= real_fodder[i];
    new_key[starting_point] = new_value;
  }

  return true;
}

byte key_part_8[8] = { 0xdb, 0x2b, 0x0a, 0x5c, 0x29, 0xab, 0xf1, 0x57 };
byte key_part_3[8] = { 0x94, 0x83, 0xc2, 0x5e, 0xd1, 0xf3, 0x87, 0x47 };
byte key_part_11[8] = { 0xd3, 0xb8, 0x3f, 0x8c, 0x5a, 0x92, 0xe3, 0xc1 };

