import parseKeys from "../parse-asn1"; import randomBytes from "../randombytes"; import createHash from "../create-hash"; import mgf from "./mgf"; import xor from "./xor"; import BN from "../bn.js"; import withPublic from "./withPublic"; import crt from "../browserify-rsa"; 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; } export default (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); } });