kaven-utils
Version:
Utils for Node.js.
129 lines (128 loc) • 6.41 kB
JavaScript
/********************************************************************
* @author: Kaven
* @email: kaven@wuwenkai.com
* @website: http://blog.kaven.xyz
* @file: [Kaven-Utils] /src/KavenUtility.Crypto.ts
* @create: 2020-07-11 09:17:40.793
* @modify: 2025-10-14 22:58:04.821
* @version: 6.1.0
* @times: 23
* @lines: 183
* @copyright: Copyright © 2020-2025 Kaven. All Rights Reserved.
* @description: [description]
* @license: [license]
********************************************************************/
import { GeneratePassword, String2StringArray, StringArray2String, Strings_DoubleQuotes, SurroundBy } from "kaven-basic";
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
import { GeneratedCertificateFiles } from "./GeneratedCertificateFiles.js";
import { Execute } from "./KavenUtility.ChildProcess.js";
import { AppendPathThenCreateParentDirectory } from "./KavenUtility.FileSystem.js";
import { CertificateSubjectToString } from "./KavenUtility.js";
/**
* @since 2.0.7
* @version 2020-07-11
*/
export function GenerateEncryptPassword(keySize = 32, ivSize = 16) {
// Use the async `scrypt()` instead.
const key = scryptSync(GeneratePassword(32), GeneratePassword(32), keySize);
// Use `randomBytes` to generate a random iv instead of the static iv
// shown here.
const iv = randomBytes(ivSize); // Buffer.alloc(16, 0); // Initialization vector.
return StringArray2String(key.toString("hex"), iv.toString("hex"));
}
/**
*
* @param str some clear text data
* @param password Password used to generate key, use `GenerateEncryptPassword` to generate it.
* @param algorithm
* @since 2.0.7
* @version 2020-07-11
*/
export function EncryptString(str, password, algorithm = "aes-256-cbc") {
const strArray = String2StringArray(password);
if (strArray && strArray.length === 2) {
const key = Buffer.from(strArray[0], "hex");
const iv = Buffer.from(strArray[1], "hex");
const cipher = createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(str, "utf8", "hex");
encrypted += cipher.final("hex");
return encrypted;
}
throw new Error("Invalid Password");
}
/**
*
* @param encryptedStr
* @param password Password used to generate key
* @param algorithm
* @since 2.0.7
* @version 2020-07-11
*/
export function DecryptString(encryptedStr, password, algorithm = "aes-256-cbc") {
const strArray = String2StringArray(password);
if (strArray && strArray.length === 2) {
const key = Buffer.from(strArray[0], "hex");
const iv = Buffer.from(strArray[1], "hex");
const decipher = createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encryptedStr, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
}
throw new Error("Invalid Password");
}
/**
* Please make sure you have `openssl` already installed on your system/container.
* @param options
* @since 4.1.0
* @version 2025-10-13
*/
export async function GenerateCertificate(options) {
options ??= {};
options.caKey = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.caKey ?? "ca-key.pem");
options.caCert = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.caCert ?? "ca-cert.pem");
options.serverKey = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.serverKey ?? "server-key.pem");
options.serverReq = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.serverReq ?? "server-req.pem");
options.serverCert = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.serverCert ?? "server-cert.pem");
options.clientKey = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.clientKey ?? "client-key.pem");
options.clientReq = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.clientReq ?? "client-req.pem");
options.clientCert = AppendPathThenCreateParentDirectory(options.certGenerateDir, options.clientCert ?? "client-cert.pem");
options.size = options?.size ?? 2048;
options.days = options?.days ?? 365;
let openssl = "openssl";
if (options.openssl) {
openssl = `"${openssl}"`;
}
let { caKey, caCert, serverKey, serverReq, serverCert, clientKey, clientReq, clientCert, } = options;
caKey = SurroundBy(caKey, Strings_DoubleQuotes);
caCert = SurroundBy(caCert, Strings_DoubleQuotes);
serverKey = SurroundBy(serverKey, Strings_DoubleQuotes);
serverReq = SurroundBy(serverReq, Strings_DoubleQuotes);
serverCert = SurroundBy(serverCert, Strings_DoubleQuotes);
clientKey = SurroundBy(clientKey, Strings_DoubleQuotes);
clientReq = SurroundBy(clientReq, Strings_DoubleQuotes);
clientCert = SurroundBy(clientCert, Strings_DoubleQuotes);
const commands = [
// 1. Creating the Certificate Authority's Certificate and Keys
// Generate a private key for the CA
`${openssl} genrsa -out ${caKey} ${options.size}`,
// Generate the X509 certificate for the CA
`${openssl} req -new -x509 -nodes -days ${options.days} -key ${caKey} -out ${caCert} ${CertificateSubjectToString(options.caSubj)}`,
// 2. Creating the Server's Certificate and Keys
// Generate the private key and certificate request
`${openssl} req -newkey rsa:${options.size} -nodes -keyout ${serverKey} -out ${serverReq} ${CertificateSubjectToString(options?.serverSubj)}`,
// Generate the X509 certificate for the server
`${openssl} x509 -req -days ${options.days} -in ${serverReq} -out ${serverCert} -CA ${caCert} -CAkey ${caKey}`,
// 3. Creating the Client's Certificate and Keys
// Generate the private key and certificate request
`${openssl} req -newkey rsa:${options.size} -nodes -keyout ${clientKey} -out ${clientReq} ${CertificateSubjectToString(options?.clientSubj)}`,
// Generate the X509 certificate for the server
`${openssl} x509 -req -days ${options.days} -in ${clientReq} -out ${clientCert} -CA ${caCert} -CAkey ${caKey}`,
];
for (const command of commands) {
await Execute(command, {
logger: options.logger,
});
}
const result = new GeneratedCertificateFiles(options);
return result;
}