95 lines
2.4 KiB
JavaScript
95 lines
2.4 KiB
JavaScript
|
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;
|
||
|
}
|