| 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 constants = { |
| RSA_PKCS1_OAEP_PADDING: 4, |
| RSA_PKCS1_PADDIN: 1, |
| RSA_NO_PADDING: 3 |
| }; |
| |
| module.exports = function publicEncrypt(public_key, msg, reverse) { |
| var padding; |
| if (public_key.padding) { |
| padding = public_key.padding; |
| } else if (reverse) { |
| padding = 1; |
| } else { |
| padding = 4; |
| } |
| var key = parseKeys(public_key); |
| 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(new Buffer('')).digest(); |
| var hLen = iHash.length; |
| var hLen2 = 2 * hLen; |
| if (mLen > k - hLen2 - 2) { |
| throw new Error('message too long'); |
| } |
| var ps = new Buffer(k - mLen - hLen2 - 2); |
| ps.fill(0); |
| var dblen = k - hLen - 1; |
| var seed = randomBytes(hLen); |
| var maskedDb = xor(Buffer.concat([iHash, ps, new Buffer([1]), msg], dblen), mgf(seed, dblen)); |
| var maskedSeed = xor(seed, mgf(maskedDb, hLen)); |
| return new bn(Buffer.concat([new Buffer([0]), 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 = new Buffer(k - mLen - 3); |
| ps.fill(0xff); |
| } else { |
| ps = nonZero(k - mLen - 3); |
| } |
| return new bn(Buffer.concat([new Buffer([0, reverse?1:2]), ps, new Buffer([0]), msg], k)); |
| } |
| function nonZero(len, crypto) { |
| var out = new Buffer(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; |
| } |