Files
utils/src/components/tools/CryptoTools.vue
zguiy 8400dbfab9
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
工具完成
2025-06-28 22:38:49 +08:00

418 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="space-y-6">
<!-- 算法选择 -->
<div class="card p-4">
<h3 class="text-md font-medium text-primary mb-3">选择加密算法</h3>
<div class="grid grid-cols-2 md:grid-cols-6 gap-2">
<button
v-for="algorithm in algorithms"
:key="algorithm.type"
:class="[
'px-3 py-2 text-sm font-medium rounded transition-all',
activeAlgorithm === algorithm.type
? 'bg-primary text-white shadow-sm'
: 'bg-block text-secondary border hover:bg-hover'
]"
@click="setActiveAlgorithm(algorithm.type)"
>
{{ algorithm.name }}
</button>
</div>
</div>
<!-- 操作模式选择仅对支持编码/解码的算法显示 -->
<div v-if="currentAlgorithm?.isEncodeDecode" class="card p-4">
<h3 class="text-md font-medium text-primary mb-3">操作模式</h3>
<div class="flex gap-2">
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
!isDecoding ? 'bg-primary text-white' : 'bg-block text-secondary border'
]"
@click="isDecoding = false"
>
{{ currentAlgorithm?.type === 'aes' ? '加密' : '编码' }}
</button>
<button
:class="[
'flex-1 px-4 py-2 text-sm font-medium rounded transition-all',
isDecoding ? 'bg-primary text-white' : 'bg-block text-secondary border'
]"
@click="isDecoding = true"
>
{{ currentAlgorithm?.type === 'aes' ? '解密' : '解码' }}
</button>
</div>
</div>
<!-- 输入和处理区域 -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- 输入区域 -->
<div class="card p-4">
<div class="flex items-center justify-between mb-3">
<h3 class="text-md font-medium text-primary">输入内容</h3>
<div class="flex gap-2">
<button @click="loadExample" class="btn-secondary text-sm">
<FontAwesomeIcon :icon="['fas', 'redo']" class="mr-1" />
示例
</button>
<button @click="clearAll" class="btn-secondary text-sm">
<FontAwesomeIcon :icon="['fas', 'eraser']" class="mr-1" />
清空
</button>
</div>
</div>
<div class="space-y-4">
<!-- 密钥输入仅对需要密钥的算法显示 -->
<div v-if="currentAlgorithm?.needsKey">
<label class="block text-sm text-secondary font-medium mb-2">密钥</label>
<input
v-model="secretKey"
type="text"
class="input-field w-full"
placeholder="请输入加密密钥..."
/>
</div>
<!-- 文本输入 -->
<div>
<label class="block text-sm text-secondary font-medium mb-2">
{{ isDecoding && currentAlgorithm?.isEncodeDecode ? '待解密/解码内容' : '待加密/编码内容' }}
</label>
<textarea
v-model="inputText"
class="textarea-field h-36 w-full font-mono resize-y"
:placeholder="getInputPlaceholder()"
/>
</div>
<!-- 处理按钮 -->
<button
@click="processOperation"
class="btn-primary w-full flex items-center justify-center gap-2"
:disabled="!inputText.trim() || (currentAlgorithm?.needsKey && !secretKey.trim())"
>
<FontAwesomeIcon :icon="['fas', 'lock']" />
{{ getProcessButtonText() }}
</button>
</div>
</div>
<!-- 输出区域 -->
<div class="card p-4">
<div class="flex items-center justify-between mb-3">
<h3 class="text-md font-medium text-primary">输出结果</h3>
<button
v-if="output"
@click="copyToClipboard"
class="btn-secondary text-sm"
:disabled="!output"
>
<FontAwesomeIcon :icon="copied ? ['fas', 'check'] : ['fas', 'copy']" class="mr-1" />
{{ copied ? '已复制' : '复制' }}
</button>
</div>
<div class="space-y-4">
<!-- 结果显示 -->
<div>
<label class="block text-sm text-secondary font-medium mb-2">
{{ isDecoding && currentAlgorithm?.isEncodeDecode ? '解密/解码结果' : '加密/编码结果' }}
</label>
<textarea
v-model="output"
readonly
class="textarea-field h-36 w-full font-mono resize-y bg-block"
placeholder="结果将在这里显示..."
/>
</div>
<!-- 结果信息 -->
<div v-if="output" class="text-sm text-tertiary">
<div>字符长度: {{ output.length }}</div>
<div v-if="currentAlgorithm?.type !== 'aes' && !isDecoding">
哈希值: {{ currentAlgorithm?.name }}
</div>
</div>
</div>
</div>
</div>
<!-- 错误和成功消息 -->
<div v-if="error" class="p-3 bg-red-900/20 border border-red-700/30 rounded-lg text-error">
<FontAwesomeIcon :icon="['fas', 'exclamation-triangle']" class="mr-2" />
{{ error }}
</div>
<div v-if="success" class="p-3 bg-green-900/20 border border-green-700/30 rounded-lg text-green-400">
<FontAwesomeIcon :icon="['fas', 'check']" class="mr-2" />
{{ success }}
</div>
<!-- 算法说明 -->
<div class="card p-4">
<h3 class="text-md font-medium text-primary mb-3">
<FontAwesomeIcon :icon="['fas', 'info-circle']" class="mr-2" />
算法说明
</h3>
<div class="text-sm text-secondary">
{{ getAlgorithmDescription() }}
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import CryptoJS from 'crypto-js'
// 加密算法类型
type CryptoType = 'md5' | 'sha1' | 'sha256' | 'sha512' | 'aes' | 'base64'
// 算法配置
interface AlgorithmConfig {
type: CryptoType
name: string
needsKey: boolean
isEncodeDecode: boolean
description: string
}
// 响应式状态
const activeAlgorithm = ref<CryptoType>('md5')
const inputText = ref('')
const secretKey = ref('')
const output = ref('')
const isDecoding = ref(false)
const copied = ref(false)
const error = ref<string | null>(null)
const success = ref<string | null>(null)
// 算法配置
const algorithms: AlgorithmConfig[] = [
{
type: 'md5',
name: 'MD5',
needsKey: false,
isEncodeDecode: false,
description: 'MD5是一种广泛使用的密码散列函数可以产生出一个128位16字节的散列值。常用于文件校验和密码存储。'
},
{
type: 'sha1',
name: 'SHA1',
needsKey: false,
isEncodeDecode: false,
description: 'SHA-1是一种密码散列函数可以产生一个160位20字节的散列值。比MD5更安全但现在也被认为不够安全。'
},
{
type: 'sha256',
name: 'SHA256',
needsKey: false,
isEncodeDecode: false,
description: 'SHA-256是SHA-2家族的一种可以产生一个256位32字节的散列值。目前被认为是安全的哈希算法。'
},
{
type: 'sha512',
name: 'SHA512',
needsKey: false,
isEncodeDecode: false,
description: 'SHA-512是SHA-2家族的一种可以产生一个512位64字节的散列值。比SHA-256更安全计算量也更大。'
},
{
type: 'aes',
name: 'AES',
needsKey: true,
isEncodeDecode: true,
description: 'AES高级加密标准是一种对称加密算法需要相同的密钥进行加密和解密。广泛用于数据保护。'
},
{
type: 'base64',
name: 'Base64',
needsKey: false,
isEncodeDecode: true,
description: 'Base64是一种编码方式常用于在文本环境中传输二进制数据。不是加密算法只是编码转换。'
}
]
// 当前算法配置
const currentAlgorithm = computed(() =>
algorithms.find(algo => algo.type === activeAlgorithm.value)
)
// 获取输入提示文本
const getInputPlaceholder = (): string => {
if (isDecoding.value && currentAlgorithm.value?.isEncodeDecode) {
return currentAlgorithm.value.type === 'aes'
? '请输入要解密的密文...'
: '请输入要解码的内容...'
}
return '请输入要处理的文本内容...'
}
// 获取处理按钮文本
const getProcessButtonText = (): string => {
if (!currentAlgorithm.value) return '处理'
if (currentAlgorithm.value.isEncodeDecode) {
return isDecoding.value
? (currentAlgorithm.value.type === 'aes' ? '解密' : '解码')
: (currentAlgorithm.value.type === 'aes' ? '加密' : '编码')
}
return '生成哈希'
}
// 获取算法描述
const getAlgorithmDescription = (): string => {
return currentAlgorithm.value?.description || ''
}
// 设置活动算法
const setActiveAlgorithm = (type: CryptoType) => {
activeAlgorithm.value = type
output.value = ''
error.value = null
success.value = null
// 如果不支持编码/解码,重置解码状态
if (!currentAlgorithm.value?.isEncodeDecode) {
isDecoding.value = false
}
}
// 处理操作
const processOperation = () => {
error.value = null
success.value = null
output.value = ''
if (!inputText.value.trim()) {
error.value = '请输入要处理的内容'
return
}
if (currentAlgorithm.value?.needsKey && !secretKey.value.trim()) {
error.value = '请输入密钥'
return
}
try {
let result = ''
switch (activeAlgorithm.value) {
case 'md5':
result = CryptoJS.MD5(inputText.value).toString()
break
case 'sha1':
result = CryptoJS.SHA1(inputText.value).toString()
break
case 'sha256':
result = CryptoJS.SHA256(inputText.value).toString()
break
case 'sha512':
result = CryptoJS.SHA512(inputText.value).toString()
break
case 'aes':
if (isDecoding.value) {
// 解密操作
try {
const decrypted = CryptoJS.AES.decrypt(inputText.value, secretKey.value)
result = decrypted.toString(CryptoJS.enc.Utf8)
if (!result) {
throw new Error('解密失败,请检查密文和密钥是否正确')
}
} catch {
throw new Error('解密失败,请检查密文和密钥是否正确')
}
} else {
// 加密操作
result = CryptoJS.AES.encrypt(inputText.value, secretKey.value).toString()
}
break
case 'base64':
if (isDecoding.value) {
// Base64解码
try {
result = CryptoJS.enc.Base64.parse(inputText.value).toString(CryptoJS.enc.Utf8)
} catch {
throw new Error('Base64解码失败请检查输入内容格式')
}
} else {
// Base64编码
result = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(inputText.value))
}
break
}
output.value = result
success.value = isDecoding.value ? '解密/解码成功' : '加密/编码成功'
} catch (err) {
console.error('处理错误:', err)
error.value = `处理失败: ${err instanceof Error ? err.message : '未知错误'}`
}
}
// 复制到剪贴板
const copyToClipboard = async () => {
if (!output.value) return
try {
await navigator.clipboard.writeText(output.value)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
} catch (err) {
console.error('复制失败:', err)
error.value = '复制失败'
}
}
// 清空所有内容
const clearAll = () => {
inputText.value = ''
secretKey.value = ''
output.value = ''
error.value = null
success.value = null
}
// 加载示例
const loadExample = () => {
const examples: Record<CryptoType, { input: string; key?: string }> = {
md5: { input: 'Hello, World!' },
sha1: { input: 'Hello, World!' },
sha256: { input: 'Hello, World!' },
sha512: { input: 'Hello, World!' },
aes: { input: 'Hello, World!', key: 'secret-key-12345' },
base64: { input: 'Hello, World!' }
}
const example = examples[activeAlgorithm.value]
inputText.value = example.input
if (example.key) {
secretKey.value = example.key
}
output.value = ''
error.value = null
success.value = null
}
// 清除状态提示的定时器
watch([error, success], () => {
if (error.value || success.value) {
setTimeout(() => {
error.value = null
success.value = null
}, 3000)
}
})
</script>