实现哈希和编解码

This commit is contained in:
fofolee 2024-12-30 21:11:13 +08:00
parent 1d3aa3c9ae
commit c8479373ee
7 changed files with 292 additions and 872 deletions

View File

@ -1,150 +0,0 @@
import NodeForge from "node-forge";
import { forgeBytesToStr, strToForgeBytes, dataConv } from "@/script/Common.js";
const RSAPadDict = {
"PKCS#1": {
getMaxSize: (keySize) => Math.floor((keySize - 1) / 8) - 11,
coding: (chunks, secretKey, method) =>
secretKey[method](chunks, "RSAES-PKCS1-V1_5"),
},
OAEP: {
getMaxSize: (keySize) => Math.floor(keySize / 8) - 42,
coding: (chunks, secretKey, method) =>
secretKey[method](chunks, "RSA-OAEP"),
},
"OAEP/SHA-256": {
getMaxSize: (keySize) => Math.floor(keySize / 8) - 66,
coding: (chunks, secretKey, method) =>
secretKey[method](chunks, "RSA-OAEP", {
md: NodeForge.md.sha256.create(),
}),
},
"OAEP/SHA-256/MGF1-SHA-1": {
getMaxSize: (keySize) => Math.floor(keySize / 8) - 74,
coding: (chunks, secretKey, method) =>
secretKey[method](chunks, "RSA-OAEP", {
md: NodeForge.md.sha256.create(),
mgf1: {
md: NodeForge.md.sha1.create(),
},
}),
},
};
const forgeRSAEncrypt = (bytes, padding, publicKey, outputCodec) => {
publicKey = NodeForge.pki.publicKeyFromPem(publicKey);
let keySize = publicKey.n.bitLength();
let chunks = "";
let encrypted = "";
let maxBlockSize = RSAPadDict[padding].getMaxSize(keySize);
for (let i = 0; i < bytes.length / maxBlockSize; i++) {
chunks = bytes.substring(i * maxBlockSize, (i + 1) * maxBlockSize);
chunks = RSAPadDict[padding].coding(chunks, publicKey, "encrypt");
encrypted += chunks;
}
return outputCodec === "Base64"
? NodeForge.util.encode64(encrypted)
: NodeForge.util.bytesToHex(encrypted);
};
const forgeRSADecrypt = (cipher, padding, privateKey, inputCodec) => {
let bytes =
inputCodec === "Base64"
? NodeForge.util.decode64(cipher)
: NodeForge.util.hexToBytes(cipher);
privateKey = NodeForge.pki.privateKeyFromPem(privateKey);
let keySize = privateKey.n.bitLength();
let maxBlockSize = keySize / 8;
let decrypted = "";
let chunks = "";
for (let i = 0; i < bytes.length / maxBlockSize; i++) {
chunks = bytes.substring(i * maxBlockSize, (i + 1) * maxBlockSize);
chunks = RSAPadDict[padding].coding(chunks, privateKey, "decrypt");
decrypted += chunks;
}
return decrypted;
};
export const RSA = {
name: "RSA",
params: [
{
type: "list",
options: ["PKCS#1", "OAEP", "OAEP/SHA-256", "OAEP/SHA-256/MGF1-SHA-1"],
value: "PKCS#1",
},
{
type: "text",
name: "公钥",
value: ["", "Pem"],
options: ["Pem", "Hex", "Base64"],
id: "publicKey",
},
{
type: "text",
name: "私钥",
value: ["", "Pem"],
options: ["Pem", "Hex", "Base64"],
id: "privateKey",
},
{
type: "list",
options: ["Hex", "Base64"],
value: "Base64",
},
],
actions: [
{
type: "action",
name: "生成密钥",
component: "GenerateKeypair",
},
{
type: "action",
name: "CTF",
component: "RsaCtf",
},
],
encrypt: (
msg,
padding = "PKCS#1",
[pubKey = "", pubKeyCodec = "Pem"],
// eslint-disable-next-line no-unused-vars
[priKey = "", priKeyCodec = "Pem"],
outputCodec = "Base64",
{ inputCodec }
) => {
if (!pubKey) throw "缺少公钥";
if (pubKeyCodec !== "Pem") {
pubKey =
"-----BEGIN PUBLIC KEY-----\n" +
dataConv(pubKey, pubKeyCodec, "Base64") +
"\n-----END PUBLIC KEY-----";
}
pubKey = pubKey.replace(/\\n/g, "\n");
let bytes = strToForgeBytes(msg, inputCodec);
let cipher = forgeRSAEncrypt(bytes, padding, pubKey, outputCodec);
if (!cipher) throw "加密失败";
return cipher;
},
decrypt: (
cipher,
padding = "PKCS#1",
// eslint-disable-next-line no-unused-vars
[pubKey = "", pubKeyCodec = "Pem"],
[priKey = "", priKeyCodec = "Pem"],
codec = "Base64"
) => {
if (!priKey) return "缺少私钥";
if (priKeyCodec !== "Pem") {
priKey =
"-----BEGIN PRIVATE KEY-----\n" +
dataConv(priKey, priKeyCodec, "Base64") +
"\n-----END PRIVATE KEY-----";
}
priKey = priKey.replace(/\\n/g, "\n");
let msg = forgeRSADecrypt(cipher, padding, priKey, codec);
if (!msg) throw "解密失败";
return forgeBytesToStr(msg);
},
};

View File

@ -1,149 +0,0 @@
import { strToBytesArray, bytesArrayToStr, dataConv } from "@/script/Common.js";
import { processSecret } from "./SymmetricEncryption.js";
import SM from "sm-crypto";
export const SM4 = {
name: "SM4",
params: [
{
type: "text",
name: "Key",
value: ["", "Utf8"],
options: ["Utf8", "Hex", "Base64"],
},
{
type: "text",
name: "IV",
value: ["", "Utf8"],
options: ["Utf8", "Hex", "Base64"],
id: "IV",
},
{
type: "list",
options: ["ECB", "CBC"],
value: "ECB",
banList: {
ECB: ["IV"],
},
id: "mode",
},
{ type: "list", options: ["pkcs#7", "none"], value: "pkcs#7" },
{ type: "list", options: ["Base64", "Hex"], value: "Base64" },
],
encrypt: (
msg,
key,
iv = "",
mode = "ECB",
padding = "pkcs#7",
outputCodec = "Base64",
{ inputCodec }
) => {
let bytesArray = strToBytesArray(msg, inputCodec);
return dataConv(
SM.sm4.encrypt(bytesArray, processSecret(key, 16, "hex"), {
mode: mode.toLowerCase(),
iv: processSecret(iv, 16, "hex"),
padding: padding,
}),
"Hex",
outputCodec
);
},
decrypt: (
cipher,
key,
iv = "",
mode = "ECB",
padding = "pkcs#7",
codec = "Base64"
) => {
let bytesArray = SM.sm4.decrypt(
dataConv(cipher, codec, "Hex"),
processSecret(key, 16, "hex"),
{
mode: mode.toLowerCase(),
iv: processSecret(iv, 16, "hex"),
padding: padding,
output: "array",
}
);
return bytesArrayToStr(bytesArray);
},
};
export const SM2 = {
name: "SM2",
params: [
{
type: "text",
name: "公钥",
value: ["", "Base64"],
options: ["Hex", "Base64"],
id: "publicKey",
},
{
type: "text",
name: "私钥",
value: ["", "Base64"],
options: ["Hex", "Base64"],
id: "privateKey",
},
{
type: "list",
options: [
{ label: "C1C3C2", value: 1 },
{ label: "C1C2C3", value: 0 },
],
value: 1,
},
{
type: "list",
options: ["Hex", "Base64"],
value: "Base64",
},
],
actions: [
{
type: "action",
name: "生成密钥",
component: "GenerateKeypair",
},
],
encrypt: (
msg,
[pubKey = "", pubKeyCodec = "Base64"],
// eslint-disable-next-line no-unused-vars
[priKey = "", priKeyCodec = "Base64"],
cipherMode = 1,
outputCodec = "Base64",
{ inputCodec }
) => {
if (!pubKey) throw "缺少公钥";
pubKey = dataConv(pubKey, pubKeyCodec, "Hex");
let cipher = SM.sm2.doEncrypt(
strToBytesArray(msg, inputCodec),
pubKey,
cipherMode
);
if (!cipher) throw "加密失败";
return dataConv(cipher, "Hex", outputCodec);
},
decrypt: (
cipher,
// eslint-disable-next-line no-unused-vars
[pubKey = "", pubKeyCodec = "Base64"],
[priKey = "", priKeyCodec = "Base64"],
cipherMode = 1,
codec = "Base64"
) => {
if (!priKey) return "缺少私钥";
priKey = dataConv(priKey, priKeyCodec, "Hex");
cipher = dataConv(cipher, codec, "Hex");
let msg = SM.sm2.doDecrypt(cipher, priKey, cipherMode, {
output: "array",
});
if (!msg?.length) throw "解密失败";
return bytesArrayToStr(msg);
},
};

View File

@ -1,280 +0,0 @@
import CryptoJS from "crypto-js";
import NodeForge from "node-forge";
import {
strToWordArray,
forgeBytesToStr,
wordArrayToStr,
dataConv,
} from "@/script/Common.js";
let symmetricEncryptionParams = [
{
type: "text",
name: "Key",
value: ["", "Utf8"],
options: ["Utf8", "Hex", "Base64"],
},
{
type: "text",
name: "IV",
value: ["", "Utf8"],
options: ["Utf8", "Hex", "Base64"],
// name 会改变元素样式额外增加ID作为唯一标识
id: "IV",
},
{
type: "list",
options: Object.keys(CryptoJS.mode),
value: "ECB",
// 根据banList禁用指定ID的元素例如选中ECB时禁用IVban和被ban的元素必须要有id
banList: {
ECB: ["IV"],
},
id: "mode",
},
{
type: "list",
options: [128, 192, 256],
value: 128,
},
{
type: "list",
options: Object.keys(CryptoJS.pad),
value: "Pkcs7",
id: "padding",
},
{ type: "list", options: ["Base64", "Hex"], value: "Base64" },
];
// AES添加GCM模式
let symmetricEncryptionParamsAes = JSON.parse(
JSON.stringify(symmetricEncryptionParams)
);
symmetricEncryptionParamsAes[2].options.push("GCM");
symmetricEncryptionParamsAes[2].banList.GCM = ["padding"];
// secret 格式为 hex字符串方便补位
const adjustSecLen = (hexSecret, len) => {
return hexSecret.length >= len * 2
? hexSecret.slice(0, len * 2)
: hexSecret + "00".repeat(len - hexSecret.length / 2);
};
export const processSecret = (secretWithCodec, len, to = "wordArray") => {
let [secret, codec] = secretWithCodec;
let hexSecret = dataConv(secret, codec, "Hex");
let filledSecret = adjustSecLen(hexSecret, len);
return to === "wordArray"
? CryptoJS.enc.Hex.parse(filledSecret)
: filledSecret;
};
// key/iv bytes
const forgeAesGcmEncrypt = (msg, key, iv, outputCodec, inputCodec) => {
var cipher = NodeForge.cipher.createCipher("AES-GCM", key);
cipher.start({
iv: iv,
});
cipher.update(NodeForge.util.createBuffer(msg, inputCodec));
cipher.finish();
var encrypted = cipher.output;
return {
enc: dataConv(encrypted.toHex(), "Hex", outputCodec),
tag: dataConv(cipher.mode.tag.toHex(), "Hex", outputCodec),
};
};
// key/iv bytes
const forgeAesGcmDecrypt = (cipher, key, iv, tag, inputCodec) => {
cipher = NodeForge.util.createBuffer(
NodeForge.util.hexToBytes(dataConv(cipher, inputCodec, "Hex"))
);
var decipher = NodeForge.cipher.createDecipher("AES-GCM", key);
decipher.start({
iv: iv,
tag: NodeForge.util.hexToBytes(dataConv(tag, inputCodec, "Hex")),
});
decipher.update(cipher);
var pass = decipher.finish();
if (pass) {
return decipher.output.getBytes();
}
return null;
};
export const AES = {
name: "AES",
params: symmetricEncryptionParamsAes,
encrypt: (
msg,
key,
iv = "",
mode = "ECB",
keySize = 128,
padding = "Pkcs7",
outputCodec = "Base64",
{ inputCodec }
) => {
if (mode === "GCM") {
key = NodeForge.util.hexToBytes(processSecret(key, keySize / 8, "hex"));
iv = NodeForge.util.hexToBytes(processSecret(iv, 16, "hex"));
let result = forgeAesGcmEncrypt(msg, key, iv, outputCodec, inputCodec);
return JSON.stringify(result, null, 2);
} else {
let encrypted = CryptoJS.AES.encrypt(
strToWordArray(msg, inputCodec),
processSecret(key, keySize / 8, "wordArray"),
{
iv: processSecret(iv, 16, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return CryptoJS.enc[outputCodec].stringify(encrypted.ciphertext);
}
},
decrypt: (
cipher,
key,
iv = "",
mode = "ECB",
keySize = 128,
padding = "Pkcs7",
codec = "Base64"
) => {
if (mode === "GCM") {
let format = `密文格式应为 {"enc":"hex or base64","tag":"hex or base64"}`;
try {
var { enc, tag } = JSON.parse(cipher);
} catch (_) {
throw new Error(format);
}
if (!enc || !tag) {
throw new Error(format);
}
key = NodeForge.util.hexToBytes(processSecret(key, keySize / 8, "hex"));
iv = NodeForge.util.hexToBytes(processSecret(iv, 16, "hex"));
let decrypted = forgeAesGcmDecrypt(enc, key, iv, tag, codec);
return forgeBytesToStr(decrypted);
} else {
cipher = dataConv(cipher, codec, "Base64");
const decrypt = CryptoJS.AES.decrypt(
cipher,
processSecret(key, keySize / 8, "wordArray"),
{
iv: processSecret(iv, 16, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return wordArrayToStr(decrypt);
}
},
};
export const DES = {
name: "DES",
params: symmetricEncryptionParams.filter((x, i) => i !== 3),
encrypt: (
msg,
key,
iv = "",
mode = "ECB",
padding = "Pkcs7",
outputCodec = "Base64",
{ inputCodec }
) => {
const encrypted = CryptoJS.DES.encrypt(
strToWordArray(msg, inputCodec),
processSecret(key, 8, "wordArray"),
{
iv: processSecret(iv, 8, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return CryptoJS.enc[outputCodec].stringify(encrypted.ciphertext);
},
decrypt: (
cipher,
key,
iv = "",
mode = "ECB",
padding = "Pkcs7",
codec = "Base64"
) => {
cipher = dataConv(cipher, codec, "Base64");
const decrypt = CryptoJS.DES.decrypt(
cipher,
processSecret(key, 8, "wordArray"),
{
iv: processSecret(iv, 8, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return wordArrayToStr(decrypt);
},
};
export const TripleDES = {
name: "TripleDES",
params: symmetricEncryptionParams.filter((x, i) => i !== 3),
encrypt: (
msg,
key,
iv = "",
mode = "ECB",
padding = "Pkcs7",
outputCodec = "Base64",
{ inputCodec }
) => {
const encrypted = CryptoJS.TripleDES.encrypt(
strToWordArray(msg, inputCodec),
processSecret(key, 8, "wordArray"),
{
iv: processSecret(iv, 8, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return CryptoJS.enc[outputCodec].stringify(encrypted.ciphertext);
},
decrypt: (
cipher,
key,
iv = "",
mode = "ECB",
padding = "Pkcs7",
codec = "Base64"
) => {
cipher = dataConv(cipher, codec, "Base64");
const decrypt = CryptoJS.TripleDES.decrypt(
cipher,
processSecret(key, 8, "wordArray"),
{
iv: processSecret(iv, 8, "wordArray"),
mode: CryptoJS.mode[mode],
padding: CryptoJS.pad[padding],
}
);
return wordArrayToStr(decrypt);
},
};
export const rc4 = {
name: "RC4",
params: [{ type: "text", name: "Key", value: "" }],
encrypt: (msg, key, { inputCodec }) =>
CryptoJS.RC4.encrypt(strToWordArray(msg, inputCodec), key).toString(),
decrypt: (cipher, key) => wordArrayToStr(CryptoJS.RC4.decrypt(cipher, key)),
};
export const rabbit = {
name: "Rabbit",
params: [{ type: "text", name: "Key", value: "" }],
encrypt: (msg, key, { inputCodec }) =>
CryptoJS.Rabbit.encrypt(strToWordArray(msg, inputCodec), key).toString(),
decrypt: (cipher, key) =>
wordArrayToStr(CryptoJS.Rabbit.decrypt(cipher, key)),
};

View File

@ -71,6 +71,140 @@ const textProcessing = {
hexDecode: function (text) {
return dataConv(text, "hex", "utf8");
},
// MD5 哈希
md5Hash: function (text) {
return NodeForge.md.md5.create().update(text).digest().toHex();
},
// SHA1 哈希
sha1Hash: function (text) {
return NodeForge.md.sha1.create().update(text).digest().toHex();
},
// SHA256 哈希
sha256Hash: function (text) {
return NodeForge.md.sha256.create().update(text).digest().toHex();
},
// SHA512 哈希
sha512Hash: function (text) {
return NodeForge.md.sha512.create().update(text).digest().toHex();
},
// SM3 哈希
sm3Hash: function (text) {
return sm3(text);
},
// 字符串反转
reverseString: function (text) {
return text.split("").reverse().join("");
},
// 字符串替换
replaceString: function (text, oldStr, newStr) {
return text.replace(oldStr, newStr);
},
// 字符串截取
substring: function (text, start, end) {
return text.substring(start, end);
},
// 正则提取
regexExtract: function (text, regex) {
const match = text.match(regex);
return match ? match[0] : "";
},
// 非对称加解密
asymmetricCrypto: function (config) {
const {
text,
algorithm,
operation,
format = "Base64",
publicKey = { key: "", codec: "Pem" },
privateKey = { key: "", codec: "Pem" },
padding = "RSAES-PKCS1-V1_5",
cipherMode = 1,
} = config;
if (algorithm === "SM2") {
if (operation === "encrypt") {
if (!publicKey.key) throw "缺少公钥";
// 转换公钥格式
const hexPubKey =
publicKey.codec === "Hex"
? publicKey.key
: dataConv(publicKey.key, publicKey.codec, "Hex");
// 加密
const cipher = sm2.doEncrypt(text, hexPubKey, cipherMode);
// 转换输出格式
return format === "Base64" ? dataConv(cipher, "Hex", "Base64") : cipher;
} else {
if (!privateKey.key) throw "缺少私钥";
// 转换私钥格式
const hexPriKey =
privateKey.codec === "Hex"
? privateKey.key
: dataConv(privateKey.key, privateKey.codec, "Hex");
// 转换输入格式
const hexCipher =
format === "Base64" ? dataConv(text, "Base64", "Hex") : text;
// 解密
const msg = sm2.doDecrypt(hexCipher, hexPriKey, cipherMode, {
output: "utf8",
});
if (!msg) throw "解密失败";
return msg;
}
} else if (algorithm === "RSA") {
if (operation === "encrypt") {
if (!publicKey.key) throw "缺少公钥";
// 转换公钥格式
let formattedPubKey = publicKey.key;
if (publicKey.codec !== "Pem") {
formattedPubKey =
"-----BEGIN RSA PUBLIC KEY-----\n" +
dataConv(publicKey.key, publicKey.codec, "Base64") +
"\n-----END RSA PUBLIC KEY-----";
}
formattedPubKey = formattedPubKey.replace(/\\n/g, "\n");
// 创建 RSA 公钥对象
const publicKeyObj = NodeForge.pki.publicKeyFromPem(formattedPubKey);
// 将文本转换为二进制数据
const binaryData = NodeForge.util.encodeUtf8(text);
// 使用指定的填充方式加密
const encrypted = publicKeyObj.encrypt(binaryData, padding);
// 转换输出格式
return format === "Base64"
? dataConv(encrypted, "binary", "Base64")
: dataConv(encrypted, "binary", "Hex");
} else {
if (!privateKey.key) throw "缺少私钥";
// 转换私钥格式
let formattedPriKey = privateKey.key;
if (privateKey.codec !== "Pem") {
formattedPriKey =
"-----BEGIN RSA PRIVATE KEY-----\n" +
dataConv(privateKey.key, privateKey.codec, "Base64") +
"\n-----END RSA PRIVATE KEY-----";
}
formattedPriKey = formattedPriKey.replace(/\\n/g, "\n");
// 创建 RSA 私钥对象
const privateKeyObj = NodeForge.pki.privateKeyFromPem(formattedPriKey);
// 转换输入格式
const binary =
format === "Base64"
? dataConv(text, "Base64", "binary")
: dataConv(text, "Hex", "binary");
// 解密
try {
const decrypted = privateKeyObj.decrypt(binary, padding);
// 将二进制数据转换回文本
return NodeForge.util.decodeUtf8(decrypted);
} catch (e) {
console.error(e);
throw "解密失败";
}
}
}
throw "不支持的算法";
},
// 对称加解密
symmetricCrypto: function (config) {
const {
@ -224,160 +358,6 @@ const textProcessing = {
return CryptoJS.enc.Utf8.stringify(decrypted);
}
},
// RSA 加密
rsaEncrypt: function (text, key) {
return crypto.publicEncrypt(key, Buffer.from(text)).toString("base64");
},
// RSA 解密
rsaDecrypt: function (text, key) {
return crypto.privateDecrypt(key, Buffer.from(text, "base64")).toString();
},
// SM4 加密
sm4Encrypt: function (text, key) {
// 将密钥转换为 16 进制字符串
const hexKey = Buffer.from(key).toString("hex");
return sm4.encrypt(text, hexKey);
},
// SM4 解密
sm4Decrypt: function (text, key) {
// 将密钥转换为 16 进制字符串
const hexKey = Buffer.from(key).toString("hex");
return sm4.decrypt(text, hexKey);
},
// SM2 加密
sm2Encrypt: function (text, key) {
return sm2.encrypt(text, key);
},
// SM2 解密
sm2Decrypt: function (text, key) {
return sm2.decrypt(text, key);
},
// MD5 哈希
md5Hash: function (text) {
return crypto.createHash("md5").update(text).digest("hex");
},
// SHA256 哈希
sha256Hash: function (text) {
return crypto.createHash("sha256").update(text).digest("hex");
},
// SM3 哈希
sm3Hash: function (text) {
return sm3(text);
},
// 字符串反转
reverseString: function (text) {
return text.split("").reverse().join("");
},
// 字符串替换
replaceString: function (text, oldStr, newStr) {
return text.replace(oldStr, newStr);
},
// 字符串截取
substring: function (text, start, end) {
return text.substring(start, end);
},
// 正则提取
regexExtract: function (text, regex) {
const match = text.match(regex);
return match ? match[0] : "";
},
// 非对称加解密
asymmetricCrypto: function (config) {
const {
text,
algorithm,
operation,
format = "Base64",
publicKey = { key: "", codec: "Pem" },
privateKey = { key: "", codec: "Pem" },
padding = "RSAES-PKCS1-V1_5",
cipherMode = 1,
} = config;
if (algorithm === "SM2") {
if (operation === "encrypt") {
if (!publicKey.key) throw "缺少公钥";
// 转换公钥格式
const hexPubKey =
publicKey.codec === "Hex"
? publicKey.key
: dataConv(publicKey.key, publicKey.codec, "Hex");
// 加密
const cipher = sm2.doEncrypt(text, hexPubKey, cipherMode);
// 转换输出格式
return format === "Base64" ? dataConv(cipher, "Hex", "Base64") : cipher;
} else {
if (!privateKey.key) throw "缺少私钥";
// 转换私钥格式
const hexPriKey =
privateKey.codec === "Hex"
? privateKey.key
: dataConv(privateKey.key, privateKey.codec, "Hex");
// 转换输入格式
const hexCipher =
format === "Base64" ? dataConv(text, "Base64", "Hex") : text;
// 解密
const msg = sm2.doDecrypt(hexCipher, hexPriKey, cipherMode, {
output: "utf8",
});
if (!msg) throw "解密失败";
return msg;
}
} else if (algorithm === "RSA") {
if (operation === "encrypt") {
if (!publicKey.key) throw "缺少公钥";
// 转换公钥格式
let formattedPubKey = publicKey.key;
if (publicKey.codec !== "Pem") {
formattedPubKey =
"-----BEGIN RSA PUBLIC KEY-----\n" +
dataConv(publicKey.key, publicKey.codec, "Base64") +
"\n-----END RSA PUBLIC KEY-----";
}
formattedPubKey = formattedPubKey.replace(/\\n/g, "\n");
// 创建 RSA 公钥对象
const publicKeyObj = NodeForge.pki.publicKeyFromPem(formattedPubKey);
// 将文本转换为二进制数据
const binaryData = NodeForge.util.encodeUtf8(text);
// 使用指定的填充方式加密
const encrypted = publicKeyObj.encrypt(binaryData, padding);
// 转换输出格式
return format === "Base64"
? dataConv(encrypted, "binary", "Base64")
: dataConv(encrypted, "binary", "Hex");
} else {
if (!privateKey.key) throw "缺少私钥";
// 转换私钥格式
let formattedPriKey = privateKey.key;
if (privateKey.codec !== "Pem") {
formattedPriKey =
"-----BEGIN RSA PRIVATE KEY-----\n" +
dataConv(privateKey.key, privateKey.codec, "Base64") +
"\n-----END RSA PRIVATE KEY-----";
}
formattedPriKey = formattedPriKey.replace(/\\n/g, "\n");
// 创建 RSA 私钥对象
const privateKeyObj = NodeForge.pki.privateKeyFromPem(formattedPriKey);
// 转换输入格式
const binary =
format === "Base64"
? dataConv(text, "Base64", "binary")
: dataConv(text, "Hex", "binary");
// 解密
try {
const decrypted = privateKeyObj.decrypt(binary, padding);
// 将二进制数据转换回文本
return NodeForge.util.decodeUtf8(decrypted);
} catch (e) {
console.error(e);
throw "解密失败";
}
}
}
throw "不支持的算法";
},
};
module.exports = textProcessing;

View File

@ -93,8 +93,10 @@
<component
:is="command.component"
v-model="argvLocal"
:command="command"
class="col"
v-if="!!command.component"
v-bind="command.componentProps || {}"
/>
<!-- 通用组件参数 -->
<template v-else>
@ -132,6 +134,7 @@ import VariableInput from "./VariableInput.vue";
import AxiosConfigEditor from "./http/AxiosConfigEditor.vue";
import SymmetricCryptoEditor from "./crypto/SymmetricCryptoEditor.vue";
import AsymmetricCryptoEditor from "./crypto/AsymmetricCryptoEditor.vue";
import FunctionSelector from "./FunctionSelector.vue";
import { validateVariableName } from "js/common/variableValidator";
export default defineComponent({
@ -143,6 +146,7 @@ export default defineComponent({
AxiosConfigEditor,
SymmetricCryptoEditor,
AsymmetricCryptoEditor,
FunctionSelector,
},
props: {
command: {

View File

@ -0,0 +1,101 @@
<template>
<div class="row q-col-gutter-sm">
<div class="col">
<VariableInput
:model-value="inputValue"
:label="inputLabel"
:command="command"
@update:model-value="handleInputChange"
/>
</div>
<div class="col-4">
<q-select
v-model="selectedFunction"
:options="options"
:label="selectLabel"
dense
filled
emit-value
map-options
@update:model-value="handleFunctionChange"
>
<template v-slot:prepend>
<q-icon :name="command.icon || 'functions'" />
</template>
</q-select>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import VariableInput from "./VariableInput.vue";
export default defineComponent({
name: "FunctionSelector",
components: {
VariableInput,
},
props: {
modelValue: {
type: String,
default: "",
},
command: {
type: Object,
required: true,
},
options: {
type: Array,
required: true,
},
inputLabel: {
type: String,
default: "输入值",
},
selectLabel: {
type: String,
default: "选择函数",
},
},
emits: ["update:model-value"],
data() {
return {
selectedFunction: this.options[0]?.value || "",
inputValue: "",
};
},
watch: {
modelValue: {
immediate: true,
handler(val) {
if (!val) {
this.selectedFunction = this.options[0]?.value || "";
this.inputValue = "";
return;
}
//
const match = val.match(/(.+?)\((.*)\)/);
if (match) {
this.selectedFunction = match[1];
this.inputValue = match[2];
}
},
},
},
methods: {
generateCode() {
if (!this.selectedFunction || !this.inputValue) return "";
return `${this.selectedFunction}(${this.inputValue})`;
},
handleInputChange(value) {
this.inputValue = value;
this.$emit("update:model-value", this.generateCode());
},
handleFunctionChange(value) {
this.selectedFunction = value;
this.$emit("update:model-value", this.generateCode());
},
},
});
</script>

View File

@ -4,108 +4,61 @@ export const textProcessingCommands = {
defaultOpened: false,
commands: [
{
value: "quickcomposer.textProcessing.base64Encode",
label: "Base64编码",
config: [
{
key: "text",
label: "要编码的文本",
type: "input",
defaultValue: "",
icon: "lock",
},
],
value: "quickcomposer.textProcessing",
label: "哈希计算",
desc: "计算文本的哈希值",
icon: "enhanced_encryption",
component: "FunctionSelector",
componentProps: {
inputLabel: "要计算哈希的文本",
selectLabel: "哈希算法",
options: [
{ label: "MD5", value: "quickcomposer.textProcessing.md5Hash" },
{ label: "SHA1", value: "quickcomposer.textProcessing.sha1Hash" },
{ label: "SHA256", value: "quickcomposer.textProcessing.sha256Hash" },
{ label: "SHA512", value: "quickcomposer.textProcessing.sha512Hash" },
{ label: "SM3", value: "quickcomposer.textProcessing.sm3Hash" },
],
},
},
{
value: "quickcomposer.textProcessing.base64Decode",
label: "Base64解码",
config: [
{
key: "text",
label: "要解码的Base64文本",
type: "input",
defaultValue: "",
icon: "lock_open",
},
],
},
{
value: "quickcomposer.textProcessing.hexEncode",
label: "十六进制编码",
config: [
{
key: "text",
label: "要编码的文本",
type: "input",
defaultValue: "",
icon: "lock",
},
],
},
{
value: "quickcomposer.textProcessing.hexDecode",
label: "十六进制解码",
config: [
{
key: "text",
label: "要解码的十六进制文本",
type: "input",
defaultValue: "",
icon: "lock_open",
},
],
},
{
value: "quickcomposer.textProcessing.urlEncode",
label: "URL编码",
config: [
{
key: "text",
label: "要编码的文本",
type: "input",
defaultValue: "",
icon: "link",
},
],
},
{
value: "quickcomposer.textProcessing.urlDecode",
label: "URL解码",
config: [
{
key: "text",
label: "要解码的URL编码文本",
type: "input",
defaultValue: "",
icon: "link_off",
},
],
},
{
value: "quickcomposer.textProcessing.htmlEncode",
label: "HTML编码",
config: [
{
key: "text",
label: "要编码的文本",
type: "input",
defaultValue: "",
icon: "code",
},
],
},
{
value: "quickcomposer.textProcessing.htmlDecode",
label: "HTML解码",
config: [
{
key: "text",
label: "要解码的HTML文本",
type: "input",
defaultValue: "",
icon: "code_off",
},
],
value: "quickcomposer.textProcessing",
label: "编解码",
desc: "文本编解码",
icon: "code",
component: "FunctionSelector",
componentProps: {
inputLabel: "要编解码的文本",
selectLabel: "编解码方式",
options: [
{
label: "Base64编码",
value: "quickcomposer.textProcessing.base64Encode",
},
{
label: "Base64解码",
value: "quickcomposer.textProcessing.base64Decode",
},
{
label: "十六进制编码",
value: "quickcomposer.textProcessing.hexEncode",
},
{
label: "十六进制解码",
value: "quickcomposer.textProcessing.hexDecode",
},
{ label: "URL编码", value: "quickcomposer.textProcessing.urlEncode" },
{ label: "URL解码", value: "quickcomposer.textProcessing.urlDecode" },
{
label: "HTML编码",
value: "quickcomposer.textProcessing.htmlEncode",
},
{
label: "HTML解码",
value: "quickcomposer.textProcessing.htmlDecode",
},
],
},
},
{
value: "quickcomposer.textProcessing.reverseString",
@ -206,44 +159,5 @@ export const textProcessingCommands = {
label: "非对称加解密",
component: "AsymmetricCryptoEditor",
},
{
value: "quickcomposer.textProcessing.md5Hash",
label: "MD5哈希",
config: [
{
key: "text",
label: "要哈希的文本",
type: "input",
defaultValue: "",
icon: "enhanced_encryption",
},
],
},
{
value: "quickcomposer.textProcessing.sha256Hash",
label: "SHA256哈希",
config: [
{
key: "text",
label: "要哈希的文本",
type: "input",
defaultValue: "",
icon: "enhanced_encryption",
},
],
},
{
value: "quickcomposer.textProcessing.sm3Hash",
label: "SM3哈希",
config: [
{
key: "text",
label: "要哈希的文本",
type: "input",
defaultValue: "",
icon: "enhanced_encryption",
},
],
},
],
};