mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-07 21:46:12 +08:00
实现哈希和编解码
This commit is contained in:
parent
1d3aa3c9ae
commit
c8479373ee
@ -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);
|
||||
},
|
||||
};
|
@ -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);
|
||||
},
|
||||
};
|
@ -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时,禁用IV,ban和被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)),
|
||||
};
|
@ -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;
|
||||
|
@ -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: {
|
||||
|
101
src/components/editor/composer/FunctionSelector.vue
Normal file
101
src/components/editor/composer/FunctionSelector.vue
Normal 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>
|
@ -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",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user