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') var Buffer = require('safe-buffer').Buffer module.exports = function privateDecrypt (privateKey, enc, reverse) { var padding if (privateKey.padding) { padding = privateKey.padding } else if (reverse) { padding = 1 } else { padding = 4 } var key = parseKeys(privateKey) 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 = Buffer.alloc(k - msg.length) 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 k = key.modulus.byteLength() var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() var hLen = iHash.length 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) 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 = Buffer.from(a) b = Buffer.from(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 }