mirror of
https://github.com/node-ebics/node-ebics-client.git
synced 2025-08-14 03:35:36 +00:00
Major changes. Separating responsibilities. Orders builder, serializer.
This commit is contained in:
93
lib/crypto/Crypto.js
Normal file
93
lib/crypto/Crypto.js
Normal file
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
const BN = require('bn.js');
|
||||
|
||||
const mgf1 = require('./MGF1');
|
||||
|
||||
const modPow = (base, power, mod) => {
|
||||
let result = new BN(1);
|
||||
|
||||
while (power > 0) {
|
||||
result = power.and(new BN(1)) == 1 ? (result.mul(base)).mod(mod) : result; // eslint-disable-line
|
||||
base = (base.mul(base)).mod(mod);
|
||||
power = power.shrn(1);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const 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();
|
||||
|
||||
const ps = Buffer.from('\x00'.repeat(190));
|
||||
const db = Buffer.concat([ps, Buffer.from('\x01'), salt]);
|
||||
|
||||
const dbMask = mgf1.generate(mTickHash, db.length);
|
||||
const maskedDb = mgf1.xor(db, dbMask);
|
||||
|
||||
let maskedDbMsb = mgf1.rjust(new BN(maskedDb.slice(0, 1), 2).toString(2), 8, '0');
|
||||
|
||||
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')]);
|
||||
};
|
||||
|
||||
|
||||
module.exports = class Crypto {
|
||||
static digestPublicKey(key) {
|
||||
const str = [key.e('hex').replace(/^(0+)/g, ''), key.n('hex').replace(/^(0+)/g, '')].map(x => x.toLowerCase()).join(' ');
|
||||
|
||||
return crypto.createHash('sha256').update(str).digest('base64').trim();
|
||||
}
|
||||
|
||||
static publicEncrypt(key, data) {
|
||||
return crypto.publicEncrypt({
|
||||
key: key.toPem(),
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||
}, data);
|
||||
}
|
||||
|
||||
static privateDecrypt(key, data) {
|
||||
return crypto.privateDecrypt({
|
||||
key: key.toPem(),
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||
}, data);
|
||||
}
|
||||
|
||||
static privateSign(key, data, outputEncoding = 'base64') {
|
||||
const signer = crypto.createSign('SHA256');
|
||||
|
||||
return signer.update(data).sign(key.toPem(), outputEncoding);
|
||||
}
|
||||
|
||||
static sign(key, msg, salt = crypto.randomBytes(32)) {
|
||||
const base = new BN(emsaPSS(msg, salt));
|
||||
const power = new BN(key.d());
|
||||
const mod = new BN(key.n());
|
||||
|
||||
return (modPow(base, power, mod)).toBuffer().toString('base64');
|
||||
}
|
||||
|
||||
static pad(d) {
|
||||
const dLen = d.length;
|
||||
const len = 16 * (Math.trunc(dLen / 16) + 1);
|
||||
|
||||
return Buffer.concat([d, Buffer.from(Buffer.from([0]).toString().repeat(len - dLen - 1)), Buffer.from([len - dLen])]);
|
||||
}
|
||||
|
||||
static digestWithHash(data, algorith = 'sha256') {
|
||||
return crypto.createHash(algorith).update(data).digest();
|
||||
}
|
||||
|
||||
static nonce(outputEncoding = 'hex') {
|
||||
return crypto.randomBytes(16).toString(outputEncoding);
|
||||
}
|
||||
|
||||
static timestamp() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
};
|
48
lib/crypto/MGF1.js
Normal file
48
lib/crypto/MGF1.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
const BN = require('bn.js');
|
||||
|
||||
const MFG_LEN = 32;
|
||||
|
||||
const divceil = (a, b) => ~~(((a + b) - 1) / b); // eslint-disable-line no-bitwise
|
||||
const rjust = (string, width, padding) => {
|
||||
padding = padding || ' ';
|
||||
padding = padding.substr(0, 1);
|
||||
if (string.length < width)
|
||||
return padding.repeat(width - string.length) + string;
|
||||
return string;
|
||||
};
|
||||
const xor = (a, b) => {
|
||||
if (a.length !== b.length)
|
||||
throw new Error('Different length for a and b');
|
||||
|
||||
for (let i = 0; i < a.length; i++)
|
||||
a[i] ^= b[i]; // eslint-disable-line no-bitwise
|
||||
|
||||
return a;
|
||||
};
|
||||
const i2osp = (x, len) => {
|
||||
if (x >= 256 ** len)
|
||||
throw new Error('Integer too large');
|
||||
|
||||
return Buffer.from(rjust((Buffer.from((new BN(x)).toArray('be', 4)).toString()).replace(/\x00/gi, ''), len, '\x00')); // eslint-disable-line no-control-regex
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
generate(seed, masklen) {
|
||||
if (masklen > 4294967296 * MFG_LEN)
|
||||
throw new Error('Mask too long');
|
||||
|
||||
|
||||
const b = [];
|
||||
|
||||
for (let i = 0; i < divceil(masklen, MFG_LEN); i++)
|
||||
b[i] = crypto.createHash('sha256').update(Buffer.concat([seed, i2osp(i, 4)])).digest();
|
||||
|
||||
|
||||
return (Buffer.concat(b)).slice(0, masklen);
|
||||
},
|
||||
xor,
|
||||
rjust,
|
||||
};
|
Reference in New Issue
Block a user