sicarii
Version:
The zero dependency http2 nodejs multithreading framework
454 lines (407 loc) • 11.5 kB
JavaScript
const crypto = require('crypto'),
config = require(process.env.config_file);
const crypt = {
hmac: {
sign: function(data, secret){
try {
let cnf = config.crypt.hmac;
secret = secret || cnf.secret;
return crypto.createHmac(cnf.digest, secret).update(data).digest(cnf.encode);
} catch (err) {
return null
}
},
verify: function(data, sig, secret){
try {
let cnf = config.crypt.hmac;
secret = secret || cnf.secret;
return crypt.hmac.sign(data, secret) === sig;
} catch (err) {
return null
}
}
},
jwt: {
sign: function(claims, cb){
try {
let cnf = config.crypt.jwt,
tm = Date.now(),
header = JSON.stringify(cnf.header),
final, sig;
claims = Object.assign(cnf.claims, claims);
claims.iat = tm;
claims.exp = (tm + claims.exp);
if(claims.nbf){
claims.nbf = (tm + claims.nbf);
}
claims = JSON.stringify(claims);
final = [
Buffer.from(header).toString(cnf.encode),
Buffer.from(claims).toString(cnf.encode)
].join(cnf.separator);
sig = crypto.createHmac(cnf.digest, cnf.secret).update(final).digest(cnf.encode);
sig = [final, sig].join(cnf.separator)
if(cb){
return cb(false, sig);
}
return sig;
} catch (err) {
if(cb){
return cb(err);
}
return null;
}
},
verify: function(sig, cb){
try {
let cnf = config.crypt.jwt,
tm = Date.now(),
final, validate;
sig = sig.split(cnf.separator);
validate = [sig[0], sig[1]].join(cnf.separator)
final = crypto.createHmac(cnf.digest, cnf.secret).update(validate).digest(cnf.encode);
if(final === sig[2]){
final = JSON.parse(Buffer.from(sig[1], cnf.encode).toString());
if(final.exp < tm || final.nbf && final.nbf > tm){
final = false;
}
if(cb){
return cb(false, final);
}
return final;
} else {
if(cb){
return cb(false, false);
}
return false;
}
} catch (err) {
if(cb){
return cb(err);
}
return null;
}
}
},
pbkdf2: function(secret, salt, len, cb){
let cnf = config.crypt.pbkdf2;
if(!cb){
try {
let res = crypto.pbkdf2Sync(secret, salt, cnf.iterations, len, cnf.digest)
if(cnf.encode !== ''){
res = res.toString(cnf.encode)
}
return res;
} catch (err) {
return null
}
} else {
crypto.pbkdf2(secret, salt, len, {}, function(err,res){
if(err){return cb(err)}
if(cnf.encode !== ''){
res = res.toString(cnf.encode)
}
cb(false, res)
})
}
},
scrypt: function(secret, salt, len, cb){
let cnf = config.crypt.scrypt;
if(!cb){
try {
let res = crypto.scryptSync(secret, salt, len, {
cost: cnf.cost,
blockSize: cnf.blockSize,
parallelization: cnf.parallelization
})
if(cnf.encode !== ''){
res = res.toString(cnf.encode)
}
return res;
} catch (err) {
return null
}
} else {
crypto.scrypt(secret, salt, len, {
cost: cnf.cost,
blockSize: cnf.blockSize,
parallelization: cnf.parallelization
},function(err,result){
if(err){return cb(err)}
if(cnf.encode !== ''){
result = result.toString(cnf.encode)
}
cb(false, result);
})
}
},
rnd: function(len, encode){
try {
let res = crypto.randomBytes(len);
if(encode){
res = res.toString(encode)
}
return res;
} catch (err) {
return null
}
},
encrypt: function(text, key, cb) {
try {
let cnf = config.crypt.encryption,
defaults = cnf.settings;
const iv = crypto.randomBytes(defaults.iv_len),
cipher = crypto.createCipheriv(
[defaults.cipher, defaults.bit_len, defaults.mode].join('-'),
Buffer.from(key, defaults.encode),
iv,
{authTagLength: defaults.tag_len}
),
encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
let final;
if(['gcm', 'ocb', 'ccm'].indexOf(defaults.mode) !== -1){
final = [iv, cipher.getAuthTag(), encrypted]
} else {
final = [iv, encrypted]
}
final = Buffer.concat(final).toString(defaults.encode);
if(cb){
return cb(false, final);
}
return final;
} catch(err){
if(err){
if(cb){
return cb(err)
}
return undefined;
}
}
},
decrypt: function(encdata, key, cb) {
try {
let cnf = config.crypt.encryption,
defaults = cnf.settings,
ptext;
encdata = Buffer.from(encdata, defaults.encode);
const decipher = crypto.createDecipheriv(
[defaults.cipher, defaults.bit_len, defaults.mode].join('-'),
Buffer.from(key, defaults.encode),
encdata.slice(0, defaults.iv_len),
{authTagLength: defaults.tag_len}
);
if(['gcm', 'ocb', 'ccm'].indexOf(defaults.mode) !== -1){
let tag_slice = defaults.iv_len + defaults.tag_len;
decipher.setAuthTag(encdata.slice(defaults.iv_len, tag_slice));
ptext = decipher.update(encdata.slice(tag_slice), 'binary', 'utf8') + decipher.final('utf8');
} else {
ptext = decipher.update(encdata.slice(defaults.iv_len), 'binary', 'utf8') + decipher.final('utf8');
}
if(cb){
return cb(false, ptext);
}
return ptext;
} catch (err) {
if(err){
if(cb){
return cb(err)
}
return undefined;
}
}
},
keygen: function(){
let cnf = config.crypt.encryption;
return crypto.pbkdf2Sync(
crypto.randomBytes(cnf.secret_len),
crypto.randomBytes(cnf.secret_len),
cnf.iterations, cnf.secret_len, cnf.digest
).toString(cnf.settings.encode);
},
ecdsa: {
create: function(cb){
let cnf = config.crypt.ecdsa;
crypto.generateKeyPair('ec', {
namedCurve: cnf.curve,
publicKeyEncoding: cnf.publicKey,
privateKeyEncoding: cnf.privateKey
}, function(err, publicKey, privateKey){
if(err){return cb(err)}
let obj = {
privateKey: privateKey.toString(cnf.encode),
publicKey: publicKey.toString(cnf.encode)
}
cb(false, obj)
})
},
sign: function(key, data, cb){
try {
let cnf = config.crypt.ecdsa,
obj = cnf.privateKey;
obj.key = Buffer.from(key, cnf.encode);
key = crypto.createPrivateKey(obj);
key = crypto.createSign(cnf.hash).update(data).sign(key, cnf.encode);
if(cb){return cb(false, key)};
return key;
} catch (err) {
if(err){
if(cb){return cb(err)}
return null;
}
}
},
verify: function(key, sig, data, cb){
try {
let cnf = config.crypt.ecdsa,
obj = cnf.publicKey;
obj.key = Buffer.from(key, cnf.encode);
key = crypto.createPublicKey(obj);
key = crypto.createVerify(cnf.hash).update(data).verify(key, sig, cnf.encode);
if(cb){
return cb(false, key)
}
return key;
} catch (err) {
if(err){
if(cb){return cb(err)}
return false;
}
}
}
},
ecdh: {
create: function(cb){
try {
let cnf = config.crypt.ecdh,
obj = crypto.createECDH(cnf.curve);
obj.generateKeys();
obj = {
publicKey: obj.getPublicKey(cnf.encode),
privateKey: obj.getPrivateKey(cnf.encode)
}
if(cb){
return cb(false, obj);
}
return obj;
} catch (err) {
if(cb){return cb(err);}
return null;
}
},
compute: function(privateKey, publicKey, cb){
try {
let cnf = config.crypt.ecdh,
obj = crypto.createECDH(cnf.curve);
obj.setPrivateKey(privateKey, cnf.encode)
return obj.computeSecret(publicKey, cnf.encode, cnf.encode);
} catch (err) {
if(cb){return cb(err)}
return null;
}
}
},
rsa: {
create: function(cb){
let cnf = config.crypt.rsa;
crypto.generateKeyPair('rsa', {
modulusLength: cnf.length,
publicExponent: cnf.publicExponent,
publicKeyEncoding: cnf.publicKey,
privateKeyEncoding: cnf.privateKey
}, function(err, publicKey, privateKey){
if(err){return cb(err)}
let obj = {
publicKey: publicKey.toString(cnf.encode),
privateKey: privateKey.toString(cnf.encode)
}
cb(false, obj);
})
},
encrypt: function(key, ptext, cb){
try {
let cnf = config.crypt.rsa;
if(typeof ptext === 'string'){
ptext = Buffer.from(ptext);
}
ptext = crypto.publicEncrypt({
key: key,
oaepHash: cnf.oaepHash,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
}, ptext).toString(cnf.encode);
cb(false, ptext)
} catch (err) {
cb(err)
}
},
decrypt: function(key, ctext, cb){
try {
let cnf = config.crypt.rsa;
ctext = Buffer.from(ctext, cnf.encode);
ctext = crypto.privateDecrypt({
key: key,
oaepHash: cnf.oaepHash,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
}, ctext).toString();
cb(false, ctext)
} catch (err) {
cb(err)
}
}
},
otp: {
pad: function(len, cb){
crypto.pbkdf2(
crypto.randomBytes(len),
crypto.randomBytes(len),
config.crypt.otp.iterations,
len,
config.crypt.otp.digest,
function(err,res){
if(err){cb(err)}
cb(false, res.toString(config.crypt.otp.encode))
})
},
encrypt: function(ctext, key, cb) {
try {
key = Buffer.from(key, config.crypt.otp.encode);
if(typeof ctext !== 'object'){
ctext = Buffer.from(ctext);
}
let pl = ctext.length,
plain = ctext.subarray();
for (let x = 0; x < config.crypt.otp.rounds; x++) {
for (let i = 0; i < pl; i++) {
if ((ctext[i] + key[i]) > 255) {
ctext[i] = ctext[i] + key[i] - 255;
} else {
ctext[i] = ctext[i] + key[i];
}
}
}
cb(false,ctext.toString(config.crypt.otp.encode));
} catch (err) {
cb(err)
}
},
decrypt: function(ctext, key, cb) {
try {
key = Buffer.from(key, config.crypt.otp.encode)
ctext = Buffer.from(ctext, config.crypt.otp.encode)
let plain = ctext.subarray();
for (let x = 0; x < config.crypt.otp.rounds; x++) {
for (let i = 0; i < ctext.length; i++) {
if ((plain[i] - key[i]) < 0) {
plain[i] = 255 + plain[i] - key[i];
} else {
plain[i] = plain[i] - key[i];
}
}
}
cb(false, plain)
} catch (err) {
cb(err)
}
}
}
}
module.exports = crypt;