| 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 |
| } |