| var parseKeys = require('parse-asn1'); |
| var mgf = require('./mgf'); |
| var xor = require('./xor'); |
| var bn = require('bn.js'); |
| var crt = require('browserify-rsa'); |
| var createHash = require('create-hash'); |
| var withPublic = require('./withPublic'); |
| module.exports = function privateDecrypt(private_key, enc, reverse) { |
| var padding; |
| if (private_key.padding) { |
| padding = private_key.padding; |
| } else if (reverse) { |
| padding = 1; |
| } else { |
| padding = 4; |
| } |
| |
| var key = parseKeys(private_key); |
| var k = key.modulus.byteLength(); |
| if (enc.length > k || new bn(enc).cmp(key.modulus) >= 0) { |
| throw new Error('decryption error'); |
| } |
| var msg; |
| if (reverse) { |
| msg = withPublic(new bn(enc), key); |
| } else { |
| msg = crt(enc, key); |
| } |
| var zBuffer = new Buffer(k - msg.length); |
| zBuffer.fill(0); |
| msg = Buffer.concat([zBuffer, msg], k); |
| if (padding === 4) { |
| return oaep(key, msg); |
| } else if (padding === 1) { |
| return pkcs1(key, msg, reverse); |
| } else if (padding === 3) { |
| return msg; |
| } else { |
| throw new Error('unknown padding'); |
| } |
| }; |
| |
| function oaep(key, msg){ |
| var n = key.modulus; |
| var k = key.modulus.byteLength(); |
| var mLen = msg.length; |
| var iHash = 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)); |
| var db = xor(maskedDb, mgf(seed, k - hLen - 1)); |
| 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, reverse){ |
| 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' && !reverse) || (p1.toString('hex') !== '0001' && reverse)){ |
| status++; |
| } |
| if (ps.length < 8) { |
| status++; |
| } |
| if (status) { |
| throw new Error('decryption error'); |
| } |
| return msg.slice(i); |
| } |
| function compare(a, b){ |
| a = new Buffer(a); |
| b = new Buffer(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; |
| } |