var _=require("../utils")._,crypt=require("crypto"),BigInteger=require("./jsbn.js"),utils=require("../utils.js"),schemes=require("../schemes/schemes.js"),encryptEngines=require("../encryptEngines/encryptEngines.js");exports.BigInteger=BigInteger,module.exports.Key=function(){function e(){this.n=null,this.e=0,this.d=null,this.p=null,this.q=null,this.dmp1=null,this.dmq1=null,this.coeff=null}return e.prototype.setOptions=function(e){var t=schemes[e.signingScheme],i=schemes[e.encryptionScheme];t===i?this.signingScheme=this.encryptionScheme=i.makeScheme(this,e):(this.encryptionScheme=i.makeScheme(this,e),this.signingScheme=t.makeScheme(this,e)),this.encryptEngine=encryptEngines.getEngine(this,e)},e.prototype.generate=function(e,t){var i=e>>1;this.e=parseInt(t,16);for(var n=new BigInteger(t,16);;){for(;this.p=new BigInteger(e-i,1),0!==this.p.subtract(BigInteger.ONE).gcd(n).compareTo(BigInteger.ONE)||!this.p.isProbablePrime(10););for(;this.q=new BigInteger(i,1),0!==this.q.subtract(BigInteger.ONE).gcd(n).compareTo(BigInteger.ONE)||!this.q.isProbablePrime(10););if(this.p.compareTo(this.q)<=0){var r=this.p;this.p=this.q,this.q=r}var s=this.p.subtract(BigInteger.ONE),h=this.q.subtract(BigInteger.ONE),c=s.multiply(h);if(0===c.gcd(n).compareTo(BigInteger.ONE)){if(this.n=this.p.multiply(this.q),this.n.bitLength()<e)continue;this.d=n.modInverse(c),this.dmp1=this.d.mod(s),this.dmq1=this.d.mod(h),this.coeff=this.q.modInverse(this.p);break}}this.$$recalculateCache()},e.prototype.setPrivate=function(e,t,i,n,r,s,h,c){if(!(e&&t&&i&&e.length>0&&(_.isNumber(t)||t.length>0)&&i.length>0))throw Error("Invalid RSA private key");this.n=new BigInteger(e),this.e=_.isNumber(t)?t:utils.get32IntFromBuffer(t,0),this.d=new BigInteger(i),n&&r&&s&&h&&c&&(this.p=new BigInteger(n),this.q=new BigInteger(r),this.dmp1=new BigInteger(s),this.dmq1=new BigInteger(h),this.coeff=new BigInteger(c)),this.$$recalculateCache()},e.prototype.setPublic=function(e,t){if(!(e&&t&&e.length>0&&(_.isNumber(t)||t.length>0)))throw Error("Invalid RSA public key");this.n=new BigInteger(e),this.e=_.isNumber(t)?t:utils.get32IntFromBuffer(t,0),this.$$recalculateCache()},e.prototype.$doPrivate=function(e){if(this.p||this.q)return e.modPow(this.d,this.n);for(var t=e.mod(this.p).modPow(this.dmp1,this.p),i=e.mod(this.q).modPow(this.dmq1,this.q);t.compareTo(i)<0;)t=t.add(this.p);return t.subtract(i).multiply(this.coeff).mod(this.p).multiply(this.q).add(i)},e.prototype.$doPublic=function(e){return e.modPowInt(this.e,this.n)},e.prototype.encrypt=function(e,t){var i=[],n=[],r=e.length,s=Math.ceil(r/this.maxMessageLength)||1,h=Math.ceil(r/s||1);if(1==s)i.push(e);else for(var c=0;c<s;c++)i.push(e.slice(c*h,(c+1)*h));for(var o=0;o<i.length;o++)n.push(this.encryptEngine.encrypt(i[o],t));return Buffer.concat(n)},e.prototype.decrypt=function(e,t){if(e.length%this.encryptedDataLength>0)throw Error("Incorrect data or key");for(var i=[],n=0,r=0,s=e.length/this.encryptedDataLength,h=0;h<s;h++)r=(n=h*this.encryptedDataLength)+this.encryptedDataLength,i.push(this.encryptEngine.decrypt(e.slice(n,Math.min(r,e.length)),t));return Buffer.concat(i)},e.prototype.sign=function(e){return this.signingScheme.sign.apply(this.signingScheme,arguments)},e.prototype.verify=function(e,t,i){return this.signingScheme.verify.apply(this.signingScheme,arguments)},e.prototype.isPrivate=function(){return this.n&&this.e&&this.d||!1},e.prototype.isPublic=function(e){return this.n&&this.e&&!(e&&this.d)||!1},Object.defineProperty(e.prototype,"keySize",{get:function(){return this.cache.keyBitLength}}),Object.defineProperty(e.prototype,"encryptedDataLength",{get:function(){return this.cache.keyByteLength}}),Object.defineProperty(e.prototype,"maxMessageLength",{get:function(){return this.encryptionScheme.maxMessageLength()}}),e.prototype.$$recalculateCache=function(){this.cache=this.cache||{},this.cache.keyBitLength=this.n.bitLength(),this.cache.keyByteLength=this.cache.keyBitLength+6>>3},e}();