var parseKeys = require('parse-asn1');
var mgf = require('./mgf');
var xor = require('./xor');
var bn = require('bn.js');
var crt = require('browserify-rsa');
module.exports = function (crypto) {
  return privateDecrypt;
  function privateDecrypt(private_key, enc) {
    var padding;
    if (private_key.padding) {
      padding = private_key.padding;
    } else {
      padding = 4;
    }
    
    var key = parseKeys(private_key, crypto);
    var k = key.modulus.byteLength();
    if (enc.length > k || new bn(enc).cmp(key.modulus) >= 0) {
      throw new Error('decryption error');
    }
    var msg = crt(enc, key, crypto);
    var zBuffer = new Buffer(k - msg.length);
    zBuffer.fill(0);
    msg = Buffer.concat([zBuffer, msg], k);
    if (padding === 4) {
      return oaep(key, msg, crypto);
    } else if (padding === 1) {
      return pkcs1(key, msg, crypto);
    } else if (padding === 3) {
      return msg;
    } else {
      throw new Error('unknown padding');
    }
  }
};

function oaep(key, msg, crypto){
  var n = key.modulus;
  var k = key.modulus.byteLength();
  var mLen = msg.length;
  var iHash = crypto.createHash('sha1').update(new Buffer('')).digest();
  var hLen = iHash.length;
  var hLen2 = 2 * hLen;
  if (msg[0] !== 0) {
    throw new Error('decryption error');
  }
  var maskedSeed = msg.slice(1, hLen + 1);
  var maskedDb =  msg.slice(hLen + 1);
  var seed = xor(maskedSeed, mgf(maskedDb, hLen, crypto));
  var db = xor(maskedDb, mgf(seed, k - hLen - 1, crypto));
  if (compare(iHash, db.slice(0, hLen))) {
    throw new Error('decryption error');
  }
  var i = hLen;
  while (db[i] === 0) {
    i++;
  }
  if (db[i++] !== 1) {
    throw new Error('decryption error');
  }
  return db.slice(i);
}

function pkcs1(key, msg, crypto){
  var p1 = msg.slice(0, 2);
  var i = 2;
  var status = 0;
  while (msg[i++] !== 0) {
    if (i >= msg.length) {
      status++;
      break;
    }
  }
  var ps = msg.slice(2, i - 1);
  var p2 = msg.slice(i - 1, i);

  if (p1.toString('hex') !== '0002') {
    status++;
  }
  if (ps.length < 8) {
    status++;
  }
  return  msg.slice(i);
}
function compare(a, b){
  var dif = 0;
  var len = a.length;
  if (a.length !== b.length) {
    dif++;
    len = Math.min(a.length, b.length);
  }
  var i = -1;
  while (++i < len) {
    dif += (a[i] ^ b[i]);
  }
  return dif;
}