var parseKeys = require('parse-asn1') var randomBytes = require('randombytes') var createHash = require('create-hash') var mgf = require('./mgf') var xor = require('./xor') var BN = require('bn.js') var withPublic = require('./withPublic') var crt = require('browserify-rsa') var Buffer = require('safe-buffer').Buffer module.exports = function publicEncrypt (publicKey, msg, reverse) { var padding if (publicKey.padding) { padding = publicKey.padding } else if (reverse) { padding = 1 } else { padding = 4 } var key = parseKeys(publicKey) var paddedMsg if (padding === 4) { paddedMsg = oaep(key, msg) } else if (padding === 1) { paddedMsg = pkcs1(key, msg, reverse) } else if (padding === 3) { paddedMsg = new BN(msg) if (paddedMsg.cmp(key.modulus) >= 0) { throw new Error('data too long for modulus') } } else { throw new Error('unknown padding') } if (reverse) { return crt(paddedMsg, key) } else { return withPublic(paddedMsg, key) } } function oaep (key, msg) { var k = key.modulus.byteLength() var mLen = msg.length var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() var hLen = iHash.length var hLen2 = 2 * hLen if (mLen > k - hLen2 - 2) { throw new Error('message too long') } var ps = Buffer.alloc(k - mLen - hLen2 - 2) var dblen = k - hLen - 1 var seed = randomBytes(hLen) var maskedDb = xor(Buffer.concat([iHash, ps, Buffer.alloc(1, 1), msg], dblen), mgf(seed, dblen)) var maskedSeed = xor(seed, mgf(maskedDb, hLen)) return new BN(Buffer.concat([Buffer.alloc(1), maskedSeed, maskedDb], k)) } function pkcs1 (key, msg, reverse) { var mLen = msg.length var k = key.modulus.byteLength() if (mLen > k - 11) { throw new Error('message too long') } var ps if (reverse) { ps = Buffer.alloc(k - mLen - 3, 0xff) } else { ps = nonZero(k - mLen - 3) } return new BN(Buffer.concat([Buffer.from([0, reverse ? 1 : 2]), ps, Buffer.alloc(1), msg], k)) } function nonZero (len) { var out = Buffer.allocUnsafe(len) var i = 0 var cache = randomBytes(len * 2) var cur = 0 var num while (i < len) { if (cur === cache.length) { cache = randomBytes(len * 2) cur = 0 } num = cache[cur++] if (num) { out[i++] = num } } return out }