node-ebics-client/lib/Key.js

77 lines
2.3 KiB
JavaScript
Raw Permalink Normal View History

2018-05-17 15:03:59 +00:00
'use strict';
const crypto = require('crypto');
2018-06-01 13:16:43 +00:00
const BN = require('bn.js');
const NodeRSA = require('node-rsa');
2018-06-01 13:16:43 +00:00
const mgf1 = require('./MGF1');
2018-05-17 15:03:59 +00:00
module.exports = class Key {
2018-06-01 13:16:43 +00:00
constructor(encodedKey/* , passphrase = null */) {
this.key = (encodedKey instanceof NodeRSA) ? encodedKey : new NodeRSA(encodedKey);
}
2018-05-17 15:03:59 +00:00
publicDigest() {
2018-06-01 13:16:43 +00:00
const str = [this.e().replace(/^(0+)/g, ''), this.n().replace(/^(0+)/g, '')].map(x => x.toLowerCase()).join(' ');
2018-05-17 15:03:59 +00:00
return crypto.createHash('sha256').update(str).digest('base64').trim();
2018-06-01 13:16:43 +00:00
}
2018-05-17 15:03:59 +00:00
publicEncrypt(buf) {
2018-06-01 13:16:43 +00:00
return crypto.publicEncrypt({
key: this.toPem(),
padding: crypto.constants.RSA_PKCS1_PADDING,
}, buf);
2018-05-17 15:03:59 +00:00
}
2018-06-01 13:16:43 +00:00
n() {
return this.key.exportKey('components-public').n.toString('hex', 1);
}
2018-05-17 15:03:59 +00:00
e() {
2018-06-01 13:16:43 +00:00
return new BN(this.key.exportKey('components-public').e).toBuffer().toString('hex');
}
2018-05-17 15:03:59 +00:00
toPem() {
2018-06-01 13:16:43 +00:00
return this.key.isPrivate() ? this.key.exportKey('pkcs1-private-pem') : this.key.exportKey('pkcs8-public-pem');
2018-05-17 15:03:59 +00:00
}
sign(msg, salt = crypto.randomBytes(32)) {
2018-06-01 13:16:43 +00:00
const base = new BN(Key._emsaPSS(msg, salt));
const power = new BN(this.key.keyPair.d.toBuffer());
2018-06-01 13:16:43 +00:00
const mod = new BN(this.key.keyPair.n.toBuffer());
2018-06-01 13:16:43 +00:00
return (Key._modPow(base, power, mod)).toBuffer().toString('base64');
}
2018-06-01 13:16:43 +00:00
static _emsaPSS(msg, salt) {
const eightNullBytes = Buffer.from('\x00'.repeat(8));
const digestedMsg = crypto.createHash('sha256').update(msg).digest();
const mTickHash = crypto.createHash('sha256').update(Buffer.concat([eightNullBytes, digestedMsg, salt]), 'binary').digest();
2018-06-01 13:16:43 +00:00
const ps = Buffer.from('\x00'.repeat(190));
const db = Buffer.concat([ps, Buffer.from('\x01'), salt]);
2018-06-01 13:16:43 +00:00
const dbMask = mgf1.generate(mTickHash, db.length);
const maskedDb = mgf1.xor(db, dbMask); // so far so good
2018-06-01 13:16:43 +00:00
let maskedDbMsb = mgf1.rjust(new BN(maskedDb.slice(0, 1), 2).toString(2), 8, '0');
2018-06-01 13:16:43 +00:00
maskedDbMsb = `0${maskedDbMsb.substr(1)}`;
maskedDb[0] = (new BN(maskedDbMsb, 2).toBuffer())[0]; // eslint-disable-line
return Buffer.concat([maskedDb, mTickHash, Buffer.from('BC', 'hex')]);
}
2018-06-01 13:16:43 +00:00
static _modPow(base, power, mod) {
let result = new BN(1);
2018-06-01 13:16:43 +00:00
while (power > 0) {
result = power.and(new BN(1)) === 1 ? (result.mul(base)).mod(mod) : result;
base = (base.mul(base)).mod(mod);
power = power.shrn(1);
}
return result;
}
2018-05-17 15:03:59 +00:00
};