// Generated by CoffeeScript 1.7.1
var BigInteger, NTLMResponsePayload, WritableTrackingBuffer, crypto, hex;

BigInteger = require('big-number').n;

crypto = require('crypto');

hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];

WritableTrackingBuffer = require('./tracking-buffer/writable-tracking-buffer');

NTLMResponsePayload = (function() {
  function NTLMResponsePayload(loginData) {
    this.data = this.createResponse(loginData);
  }

  NTLMResponsePayload.prototype.toString = function(indent) {
    indent || (indent = '');
    return indent + 'NTLM Auth';
  };

  NTLMResponsePayload.prototype.createResponse = function(challenge) {
    var baseIdx, bufferLength, client_nonce, data, dnIdx, domain, genTime, l2Idx, lmv2Data, lmv2len, ntIdx, ntlmData, ntlmv2len, password, server_data, server_nonce, timestamp, unIdx, username;
    client_nonce = this.createClientNonce();
    lmv2len = 24;
    ntlmv2len = 16;
    domain = challenge.domain;
    username = challenge.userName;
    password = challenge.password;
    ntlmData = challenge.ntlmpacket;
    server_data = ntlmData.target;
    server_nonce = ntlmData.nonce;
    bufferLength = 64 + (domain.length * 2) + (username.length * 2) + lmv2len + ntlmv2len + 8 + 8 + 8 + 4 + server_data.length + 4;
    data = new WritableTrackingBuffer(bufferLength);
    data.position = 0;
    data.writeString('NTLMSSP\u0000', 'utf8');
    data.writeUInt32LE(0x03);
    baseIdx = 64;
    dnIdx = baseIdx;
    unIdx = dnIdx + domain.length * 2;
    l2Idx = unIdx + username.length * 2;
    ntIdx = l2Idx + lmv2len;
    data.writeUInt16LE(lmv2len);
    data.writeUInt16LE(lmv2len);
    data.writeUInt32LE(l2Idx);
    data.writeUInt16LE(ntlmv2len);
    data.writeUInt16LE(ntlmv2len);
    data.writeUInt32LE(ntIdx);
    data.writeUInt16LE(domain.length * 2);
    data.writeUInt16LE(domain.length * 2);
    data.writeUInt32LE(dnIdx);
    data.writeUInt16LE(username.length * 2);
    data.writeUInt16LE(username.length * 2);
    data.writeUInt32LE(unIdx);
    data.writeUInt16LE(0);
    data.writeUInt16LE(0);
    data.writeUInt32LE(baseIdx);
    data.writeUInt16LE(0);
    data.writeUInt16LE(0);
    data.writeUInt32LE(baseIdx);
    data.writeUInt16LE(0x8201);
    data.writeUInt16LE(0x08);
    data.writeString(domain, 'ucs2');
    data.writeString(username, 'ucs2');
    lmv2Data = this.lmv2Response(domain, username, password, server_nonce, client_nonce);
    data.copyFrom(lmv2Data);
    genTime = (new Date).getTime();
    ntlmData = this.ntlmv2Response(domain, username, password, server_nonce, server_data, client_nonce, genTime);
    data.copyFrom(ntlmData);
    data.writeUInt32LE(0x0101);
    data.writeUInt32LE(0x0000);
    timestamp = this.createTimestamp(genTime);
    data.copyFrom(timestamp);
    data.copyFrom(client_nonce);
    data.writeUInt32LE(0x0000);
    data.copyFrom(server_data);
    data.writeUInt32LE(0x0000);
    return data.data;
  };

  NTLMResponsePayload.prototype.createClientNonce = function() {
    var client_nonce, nidx;
    client_nonce = new Buffer(8);
    nidx = 0;
    while (nidx < 8) {
      client_nonce.writeUInt8(Math.ceil(Math.random() * 255), nidx);
      nidx++;
    }
    return client_nonce;
  };

  NTLMResponsePayload.prototype.ntlmv2Response = function(domain, user, password, serverNonce, targetInfo, clientNonce, mytime) {
    var data, dataLength, hash, timestamp;
    timestamp = this.createTimestamp(mytime);
    hash = this.ntv2Hash(domain, user, password);
    dataLength = 40 + targetInfo.length;
    data = new Buffer(dataLength);
    serverNonce.copy(data, 0, 0, 8);
    data.writeUInt32LE(0x101, 8);
    data.writeUInt32LE(0x0, 12);
    timestamp.copy(data, 16, 0, 8);
    clientNonce.copy(data, 24, 0, 8);
    data.writeUInt32LE(0x0, 32);
    targetInfo.copy(data, 36, 0, targetInfo.length);
    data.writeUInt32LE(0x0, 36 + targetInfo.length);
    return this.hmacMD5(data, hash);
  };

  NTLMResponsePayload.prototype.createTimestamp = function(time) {
    var hexArray, idx, pair, tenthsOfAMicrosecond;
    tenthsOfAMicrosecond = new BigInteger(time).plus(11644473600).multiply(10000000);
    hexArray = [];
    pair = [];
    while (tenthsOfAMicrosecond.val() !== '0') {
      idx = tenthsOfAMicrosecond.mod(16);
      pair.unshift(hex[idx]);
      if (pair.length === 2) {
        hexArray.push(pair.join(''));
        pair = [];
      }
    }
    if (pair.length > 0) {
      hexArray.push(pair[0] + '0');
    }
    return new Buffer(hexArray.join(''), 'hex');
  };

  NTLMResponsePayload.prototype.lmv2Response = function(domain, user, password, serverNonce, clientNonce) {
    var data, hash, newhash, response;
    hash = this.ntv2Hash(domain, user, password);
    data = new Buffer(serverNonce.length + clientNonce.length);
    serverNonce.copy(data);
    clientNonce.copy(data, serverNonce.length, 0, clientNonce.length);
    newhash = this.hmacMD5(data, hash);
    response = new Buffer(newhash.length + clientNonce.length);
    newhash.copy(response);
    clientNonce.copy(response, newhash.length, 0, clientNonce.length);
    return response;
  };

  NTLMResponsePayload.prototype.ntv2Hash = function(domain, user, password) {
    var hash, identity;
    hash = this.ntHash(password);
    identity = new Buffer(user.toUpperCase() + domain.toUpperCase(), 'ucs2');
    return this.hmacMD5(identity, hash);
  };

  NTLMResponsePayload.prototype.ntHash = function(text) {
    var hash, md4, unicodeString;
    hash = new Buffer(21);
    hash.fill(0);
    unicodeString = new Buffer(text, 'ucs2');
    md4 = crypto.createHash('md4').update(unicodeString).digest();
    if (md4.copy) {
      md4.copy(hash);
    } else {
      new Buffer(md4, 'ascii').copy(hash);
    }
    return hash;
  };

  NTLMResponsePayload.prototype.hmacMD5 = function(data, key) {
    var hmac, result;
    hmac = crypto.createHmac('MD5', key);
    hmac.update(data);
    result = hmac.digest();
    if (result.copy) {
      return result;
    } else {
      return new Buffer(result, 'ascii').slice(0, 16);
    }
  };

  return NTLMResponsePayload;

})();

module.exports = NTLMResponsePayload;
