/*
 * JavaScript code written by Robert Mars (rmars@cisco.com) based on
 * Java code written by Jeremy Allison (jra@cygnus.com) based on
 * C code from Eric Young (eay@mincom.oz.au).
 */


/**
 * Singleton instances
 */
var int32Manipulator=new Int32Manipulator();


/**
 * Class DesKey.
 * Create a key object used by the Des and TripleDes code.
 * DesKey objects can be created from a String object, or from
 * a byte array containing 8 bytes.
 * An optional check is done for weak keys.
 */
//public class DesKey
  /**
   * DesKey constructor from an 8 byte array.
   * 
   * @param key           byte [] array, length 8.
   * @param check_key     boolean. If true checks for weak keys.
   *
   */
function DesKey(key, check_key) {
  //alert("DesKey CTOR: key="+key+", check_key="+check_key);

  this.keysced_ = new Array(128);

  this.odd_parity_array = new Array(
    1,  1,  2,  2, 4,  4,  7,  7,
    8,  8, 11, 11, 13, 13, 14, 14,
    16, 16, 19, 19, 21, 21, 22, 22,
    25, 25, 26, 26, 28, 28, 31, 31,
    32, 32, 35, 35, 37, 37, 38, 38,
    41, 41, 42, 42, 44, 44, 47, 47,
    49, 49, 50, 50, 52, 52, 55, 55,
    56, 56, 59, 59, 61, 61, 62, 62,
    64, 64, 67, 67, 69, 69, 70, 70,
    73, 73, 74, 74, 76, 76, 79, 79,
    81, 81, 82, 82, 84, 84, 87, 87,
    88, 88, 91, 91, 93, 93, 94, 94,
    97, 97, 98, 98,100,100,103,103,
    104,104,107,107,109,109,110,110,
    112,112,115,115,117,117,118,118,
    121,121,122,122,124,124,127,127,
    128,128,131,131,133,133,134,134,
    137,137,138,138,140,140,143,143,
    145,145,146,146,148,148,151,151,
    152,152,155,155,157,157,158,158,
    161,161,162,162,164,164,167,167,
    168,168,171,171,173,173,174,174,
    176,176,179,179,181,181,182,182,
    185,185,186,186,188,188,191,191,
    193,193,194,194,196,196,199,199,
    200,200,203,203,205,205,206,206,
    208,208,211,211,213,213,214,214,
    217,217,218,218,220,220,223,223,
    224,224,227,227,229,229,230,230,
    233,233,234,234,236,236,239,239,
    241,241,242,242,244,244,247,247,
    248,248,251,251,253,253,254,254
  );

  this.shifts2 = new Array(
    false, false, true, true,
    true, true, true, true,
    false, true, true, true,
    true, true, true, false
  );

  this.des_skb = new Array(8);
  //alert("typeof(this.des_skb)="+typeof(this.des_skb));
    this.des_skb[0] = new Array(
      /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
      0x00000000,0x00000010,0x20000000,0x20000010,
      0x00010000,0x00010010,0x20010000,0x20010010,
      0x00000800,0x00000810,0x20000800,0x20000810,
      0x00010800,0x00010810,0x20010800,0x20010810,
      0x00000020,0x00000030,0x20000020,0x20000030,
      0x00010020,0x00010030,0x20010020,0x20010030,
      0x00000820,0x00000830,0x20000820,0x20000830,
      0x00010820,0x00010830,0x20010820,0x20010830,
      0x00080000,0x00080010,0x20080000,0x20080010,
      0x00090000,0x00090010,0x20090000,0x20090010,
      0x00080800,0x00080810,0x20080800,0x20080810,
      0x00090800,0x00090810,0x20090800,0x20090810,
      0x00080020,0x00080030,0x20080020,0x20080030,
      0x00090020,0x00090030,0x20090020,0x20090030,
      0x00080820,0x00080830,0x20080820,0x20080830,
      0x00090820,0x00090830,0x20090820,0x20090830
    );
    //alert("typeof(this.des_skb[0])="+typeof(this.des_skb[0]));
    this.des_skb[1] = new Array(
      /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
      0x00000000,0x02000000,0x00002000,0x02002000,
      0x00200000,0x02200000,0x00202000,0x02202000,
      0x00000004,0x02000004,0x00002004,0x02002004,
      0x00200004,0x02200004,0x00202004,0x02202004,
      0x00000400,0x02000400,0x00002400,0x02002400,
      0x00200400,0x02200400,0x00202400,0x02202400,
      0x00000404,0x02000404,0x00002404,0x02002404,
      0x00200404,0x02200404,0x00202404,0x02202404,
      0x10000000,0x12000000,0x10002000,0x12002000,
      0x10200000,0x12200000,0x10202000,0x12202000,
      0x10000004,0x12000004,0x10002004,0x12002004,
      0x10200004,0x12200004,0x10202004,0x12202004,
      0x10000400,0x12000400,0x10002400,0x12002400,
      0x10200400,0x12200400,0x10202400,0x12202400,
      0x10000404,0x12000404,0x10002404,0x12002404,
      0x10200404,0x12200404,0x10202404,0x12202404
    );
    this.des_skb[2] = new Array(
      /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
      0x00000000,0x00000001,0x00040000,0x00040001,
      0x01000000,0x01000001,0x01040000,0x01040001,
      0x00000002,0x00000003,0x00040002,0x00040003,
      0x01000002,0x01000003,0x01040002,0x01040003,
      0x00000200,0x00000201,0x00040200,0x00040201,
      0x01000200,0x01000201,0x01040200,0x01040201,
      0x00000202,0x00000203,0x00040202,0x00040203,
      0x01000202,0x01000203,0x01040202,0x01040203,
      0x08000000,0x08000001,0x08040000,0x08040001,
      0x09000000,0x09000001,0x09040000,0x09040001,
      0x08000002,0x08000003,0x08040002,0x08040003,
      0x09000002,0x09000003,0x09040002,0x09040003,
      0x08000200,0x08000201,0x08040200,0x08040201,
      0x09000200,0x09000201,0x09040200,0x09040201,
      0x08000202,0x08000203,0x08040202,0x08040203,
      0x09000202,0x09000203,0x09040202,0x09040203
    );
    this.des_skb[3] = new Array(
      /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
      0x00000000,0x00100000,0x00000100,0x00100100,
      0x00000008,0x00100008,0x00000108,0x00100108,
      0x00001000,0x00101000,0x00001100,0x00101100,
      0x00001008,0x00101008,0x00001108,0x00101108,
      0x04000000,0x04100000,0x04000100,0x04100100,
      0x04000008,0x04100008,0x04000108,0x04100108,
      0x04001000,0x04101000,0x04001100,0x04101100,
      0x04001008,0x04101008,0x04001108,0x04101108,
      0x00020000,0x00120000,0x00020100,0x00120100,
      0x00020008,0x00120008,0x00020108,0x00120108,
      0x00021000,0x00121000,0x00021100,0x00121100,
      0x00021008,0x00121008,0x00021108,0x00121108,
      0x04020000,0x04120000,0x04020100,0x04120100,
      0x04020008,0x04120008,0x04020108,0x04120108,
      0x04021000,0x04121000,0x04021100,0x04121100,
      0x04021008,0x04121008,0x04021108,0x04121108
    );
    this.des_skb[4] = new Array(
      /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
      0x00000000,0x10000000,0x00010000,0x10010000,
      0x00000004,0x10000004,0x00010004,0x10010004,
      0x20000000,0x30000000,0x20010000,0x30010000,
      0x20000004,0x30000004,0x20010004,0x30010004,
      0x00100000,0x10100000,0x00110000,0x10110000,
      0x00100004,0x10100004,0x00110004,0x10110004,
      0x20100000,0x30100000,0x20110000,0x30110000,
      0x20100004,0x30100004,0x20110004,0x30110004,
      0x00001000,0x10001000,0x00011000,0x10011000,
      0x00001004,0x10001004,0x00011004,0x10011004,
      0x20001000,0x30001000,0x20011000,0x30011000,
      0x20001004,0x30001004,0x20011004,0x30011004,
      0x00101000,0x10101000,0x00111000,0x10111000,
      0x00101004,0x10101004,0x00111004,0x10111004,
      0x20101000,0x30101000,0x20111000,0x30111000,
      0x20101004,0x30101004,0x20111004,0x30111004
    );
    this.des_skb[5] = new Array(
      /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
      0x00000000,0x08000000,0x00000008,0x08000008,
      0x00000400,0x08000400,0x00000408,0x08000408,
      0x00020000,0x08020000,0x00020008,0x08020008,
      0x00020400,0x08020400,0x00020408,0x08020408,
      0x00000001,0x08000001,0x00000009,0x08000009,
      0x00000401,0x08000401,0x00000409,0x08000409,
      0x00020001,0x08020001,0x00020009,0x08020009,
      0x00020401,0x08020401,0x00020409,0x08020409,
      0x02000000,0x0A000000,0x02000008,0x0A000008,
      0x02000400,0x0A000400,0x02000408,0x0A000408,
      0x02020000,0x0A020000,0x02020008,0x0A020008,
      0x02020400,0x0A020400,0x02020408,0x0A020408,
      0x02000001,0x0A000001,0x02000009,0x0A000009,
      0x02000401,0x0A000401,0x02000409,0x0A000409,
      0x02020001,0x0A020001,0x02020009,0x0A020009,
      0x02020401,0x0A020401,0x02020409,0x0A020409
    );
    this.des_skb[6] = new Array(
      /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
      0x00000000,0x00000100,0x00080000,0x00080100,
      0x01000000,0x01000100,0x01080000,0x01080100,
      0x00000010,0x00000110,0x00080010,0x00080110,
      0x01000010,0x01000110,0x01080010,0x01080110,
      0x00200000,0x00200100,0x00280000,0x00280100,
      0x01200000,0x01200100,0x01280000,0x01280100,
      0x00200010,0x00200110,0x00280010,0x00280110,
      0x01200010,0x01200110,0x01280010,0x01280110,
      0x00000200,0x00000300,0x00080200,0x00080300,
      0x01000200,0x01000300,0x01080200,0x01080300,
      0x00000210,0x00000310,0x00080210,0x00080310,
      0x01000210,0x01000310,0x01080210,0x01080310,
      0x00200200,0x00200300,0x00280200,0x00280300,
      0x01200200,0x01200300,0x01280200,0x01280300,
      0x00200210,0x00200310,0x00280210,0x00280310,
      0x01200210,0x01200310,0x01280210,0x01280310
    );
    this.des_skb[7] = new Array(
      /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
      0x00000000,0x04000000,0x00040000,0x04040000,
      0x00000002,0x04000002,0x00040002,0x04040002,
      0x00002000,0x04002000,0x00042000,0x04042000,
      0x00002002,0x04002002,0x00042002,0x04042002,
      0x00000020,0x04000020,0x00040020,0x04040020,
      0x00000022,0x04000022,0x00040022,0x04040022,
      0x00002020,0x04002020,0x00042020,0x04042020,
      0x00002022,0x04002022,0x00042022,0x04042022,
      0x00000800,0x04000800,0x00040800,0x04040800,
      0x00000802,0x04000802,0x00040802,0x04040802,
      0x00002800,0x04002800,0x00042800,0x04042800,
      0x00002802,0x04002802,0x00042802,0x04042802,
      0x00000820,0x04000820,0x00040820,0x04040820,
      0x00000822,0x04000822,0x00040822,0x04040822,
      0x00002820,0x04002820,0x00042820,0x04042820,
      0x00002822,0x04002822,0x00042822,0x04042822
    );

  this.weak_keys = new Array(16);
    /* weak keys */
    this.weak_keys[0] = new Array(
     0x01,0x01,0x01,0x01,
     0x01,0x01,0x01,0x01);
    this.weak_keys[1] = new Array(
     0xFE,0xFE,0xFE,0xFE,
     0xFE,0xFE,0xFE,0xFE);
    this.weak_keys[2] = new Array(
     0x1F,0x1F,0x1F,0x1F,
     0x1F,0x1F,0x1F,0x1F);
    this.weak_keys[3] = new Array(
     0xE0,0xE0,0xE0,0xE0,
     0xE0,0xE0,0xE0,0xE0);
    /* semi-weak keys */
    this.weak_keys[4] = new Array(
     0x01,0xFE,0x01,0xFE,
     0x01,0xFE,0x01,0xFE);
    this.weak_keys[5] = new Array(
     0xFE,0x01,0xFE,0x01,
     0xFE,0x01,0xFE,0x01);
    this.weak_keys[6] = new Array(
     0x1F,0xE0,0x1F,0xE0,
     0x0E,0xF1,0x0E,0xF1);
    this.weak_keys[7] = new Array(
     0xE0,0x1F,0xE0,0x1F,
     0xF1,0x0E,0xF1,0x0E);
    this.weak_keys[8] = new Array(
     0x01,0xE0,0x01,0xE0,
     0x01,0xF1,0x01,0xF1);
    this.weak_keys[9] = new Array(
     0xE0,0x01,0xE0,0x01,
     0xF1,0x01,0xF1,0x01);
    this.weak_keys[10] = new Array(
     0x1F,0xFE,0x1F,0xFE,
     0x0E,0xFE,0x0E,0xFE);
    this.weak_keys[11] = new Array(
     0xFE,0x1F,0xFE,0x1F,
     0xFE,0x0E,0xFE,0x0E);
    this.weak_keys[12] = new Array(
     0x01,0x1F,0x01,0x1F,
     0x01,0x0E,0x01,0x0E);
    this.weak_keys[13] = new Array(
     0x1F,0x01,0x1F,0x01,
     0x0E,0x01,0x0E,0x01);
    this.weak_keys[14] = new Array(
     0xE0,0xFE,0xE0,0xFE,
     0xF1,0xFE,0xF1,0xFE);
    this.weak_keys[15] = new Array(
     0xFE,0xE0,0xFE,0xE0,
     0xFE,0xF1,0xFE,0xF1);

  // these 2 functions must be called after data initialization
  this.set_odd_parity(key);
  this.set_key_sced(key, check_key);
}


  /**
   * Function to return the internal byte representation of
   * the DesKey. Used internally by the Des and TripleDes
   * classes.
   * Returns a byte [].
   */
  DesKey.prototype.get_keysced=function() { return this.keysced_; }

  DesKey.prototype.check_weak_key=function(key) {
    for (var i= 0; i < this.weak_keys.length; i++) {
      var j;
      for(j = 0; j < 8; j++) {
        if(key[j] != this.weak_keys[i][j])
          break;
      }
      if(j == 8) {
        /*
         * We got a match.
         */
        return true;
      }
    }
    return false;
  }

  DesKey.prototype.check_parity=function(key) {
    var i;
    for (i=0; i<8; i++) {
      if(key[i] != this.odd_parity_array[key[i]&0xff]) {
        return false;
      }
    }
    return true;
  }

  /**
   * Add parity bits to an 8 byte array. Use this
   * before calling the DesKey constructor with this
   * array.
   *
   * @param key           byte [] array, length 8.
   */
  DesKey.prototype.set_odd_parity=function(key) {
    var i;
    for (i=0; i<8; i++) {
      key[i] = this.odd_parity_array[key[i]&0xff];
    }
  }

  /*
   * Take an 8 byte key and transform it into a des
   * key schedule.
   */
  DesKey.prototype.set_key_sced=function(key, check_key) {
    if (check_key == true) {
      /*
       * Just exit if we fail tests - caller will check.
       */
      if(check_parity(key) == false) {
        return;
      }
      if(check_weak_key(key) == true) {
        return;
      }
    }

    /*
     * Convert key to two 32 bit ints.
     */

    var key_c0 = int32Manipulator.bytes_to_int(key, 0);
    var key_d0 = int32Manipulator.bytes_to_int(key, 4);

    var tmp = 0;
    var ref_to_c0 = new Array(1);
    var ref_to_d0 = new Array(1);

    ref_to_c0[0] = key_c0;
    ref_to_d0[0] = key_d0;

    int32Manipulator.PERM_OP (ref_to_d0, ref_to_c0, tmp, 4, 0x0f0f0f0f);
    int32Manipulator.HPERM_OP(ref_to_c0, tmp, -2, 0xcccc0000);
    int32Manipulator.HPERM_OP(ref_to_d0, tmp, -2, 0xcccc0000);
    int32Manipulator.PERM_OP (ref_to_d0, ref_to_c0, tmp, 1, 0x55555555);
    int32Manipulator.PERM_OP (ref_to_c0, ref_to_d0, tmp, 8, 0x00ff00ff);
    int32Manipulator.PERM_OP (ref_to_d0, ref_to_c0, tmp, 1, 0x55555555);

    /* Convert back to ordinary ints */
    key_c0 = ref_to_c0[0];
    key_d0 = ref_to_d0[0];

    key_d0 = (((key_d0 & 0x000000ff)<<16)|(key_d0 & 0x0000ff00)|
              ((key_d0 & 0x00ff0000)>>>16)|
              ((key_c0 & 0xf0000000)>>>4));
    key_c0 &= 0x0fffffff;

    var i, tmp1;
    for (i=0; i < 16; i++) {
      if (this.shifts2[i] == true) {
        key_c0 = ((key_c0>>>2)|(key_c0<<26));
        key_d0 = ((key_d0>>>2)|(key_d0<<26));
      } else {
        key_c0 = ((key_c0>>>1)|(key_c0<<27));
        key_d0 = ((key_d0>>>1)|(key_d0<<27));
      }
      key_c0 &= 0x0fffffff;
      key_d0 &= 0x0fffffff;

      tmp1 = this.des_skb[0][ (key_c0     )&0x3f                ]|
             this.des_skb[1][((key_c0>>> 6)&0x03)|((key_c0>>> 7)&0x3c)]|
             this.des_skb[2][((key_c0>>>13)&0x0f)|((key_c0>>>14)&0x30)]|
             this.des_skb[3][((key_c0>>>20)&0x01)|((key_c0>>>21)&0x06) |
                                             ((key_c0>>>22)&0x38)];

      tmp = this.des_skb[4][ (key_d0     )&0x3f                ]|
            this.des_skb[5][((key_d0>>> 7)&0x03)|((key_d0>> 8)&0x3c)]|
            this.des_skb[6][ (key_d0>>>15)&0x3f                ]|
            this.des_skb[7][((key_d0>>>21)&0x0f)|((key_d0>>>22)&0x30)];

      /* table contained 0213 4657 */
      int32Manipulator.set_int(this.keysced_, i*8, (tmp<<16)|(tmp1&0x0000ffff));
      tmp1 = ((tmp1>>>16)|(tmp&0xffff0000));
      tmp1 = (tmp1 <<4)|(tmp1>>>28);
      int32Manipulator.set_int(this.keysced_, i*8 + 4, tmp1);
    }
  }

