核心功能: - SSH终端: 密码/密钥认证、XTerm.js终端、多主题配色、IP高亮 - SFTP管理: 双栏文件管理、上传下载、传输队列 - 端口转发: 本地/远程转发、SOCKS5动态代理、规则管理 架构改进: - 拆分大型组件 (SFTPView/TabBar/Sidebar) - 添加统一日志和错误处理 - 修复React严格模式下的终端黑屏问题 UI更新: - 新增端口转发视图 - 更新UI预览文档 - 左侧栏右键菜单支持SFTP快捷打开
96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
import crypto from 'crypto'
|
|
|
|
const ALGORITHM = 'aes-256-gcm'
|
|
const KEY_LENGTH = 32
|
|
const IV_LENGTH = 16
|
|
const TAG_LENGTH = 16
|
|
const SALT_LENGTH = 32
|
|
const ITERATIONS = 100000
|
|
|
|
// 从密码派生密钥
|
|
function deriveKey(password: string, salt: Buffer): Buffer {
|
|
return crypto.pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, 'sha256')
|
|
}
|
|
|
|
// 生成随机密钥(用于主密钥)
|
|
export function generateMasterKey(): string {
|
|
return crypto.randomBytes(KEY_LENGTH).toString('hex')
|
|
}
|
|
|
|
// 加密数据
|
|
export function encrypt(plaintext: string, password: string): string {
|
|
const salt = crypto.randomBytes(SALT_LENGTH)
|
|
const key = deriveKey(password, salt)
|
|
const iv = crypto.randomBytes(IV_LENGTH)
|
|
|
|
const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
|
|
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])
|
|
const tag = cipher.getAuthTag()
|
|
|
|
// 格式: salt:iv:tag:encrypted (全部 hex)
|
|
return [
|
|
salt.toString('hex'),
|
|
iv.toString('hex'),
|
|
tag.toString('hex'),
|
|
encrypted.toString('hex'),
|
|
].join(':')
|
|
}
|
|
|
|
// 解密数据
|
|
export function decrypt(ciphertext: string, password: string): string {
|
|
try {
|
|
const [saltHex, ivHex, tagHex, encryptedHex] = ciphertext.split(':')
|
|
|
|
if (!saltHex || !ivHex || !tagHex || !encryptedHex) {
|
|
throw new Error('Invalid ciphertext format')
|
|
}
|
|
|
|
const salt = Buffer.from(saltHex, 'hex')
|
|
const iv = Buffer.from(ivHex, 'hex')
|
|
const tag = Buffer.from(tagHex, 'hex')
|
|
const encrypted = Buffer.from(encryptedHex, 'hex')
|
|
|
|
const key = deriveKey(password, salt)
|
|
|
|
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
|
|
decipher.setAuthTag(tag)
|
|
|
|
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()])
|
|
return decrypted.toString('utf8')
|
|
} catch (error) {
|
|
throw new Error('Decryption failed: ' + (error as Error).message)
|
|
}
|
|
}
|
|
|
|
// 简单加密(不带 salt,用于可逆加密)
|
|
export function simpleEncrypt(plaintext: string, key: string): string {
|
|
const iv = crypto.randomBytes(IV_LENGTH)
|
|
const keyBuffer = Buffer.from(key, 'hex').slice(0, KEY_LENGTH)
|
|
|
|
const cipher = crypto.createCipheriv(ALGORITHM, keyBuffer, iv)
|
|
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])
|
|
const tag = cipher.getAuthTag()
|
|
|
|
return iv.toString('hex') + ':' + tag.toString('hex') + ':' + encrypted.toString('hex')
|
|
}
|
|
|
|
// 简单解密
|
|
export function simpleDecrypt(ciphertext: string, key: string): string {
|
|
try {
|
|
const [ivHex, tagHex, encryptedHex] = ciphertext.split(':')
|
|
|
|
const iv = Buffer.from(ivHex, 'hex')
|
|
const tag = Buffer.from(tagHex, 'hex')
|
|
const encrypted = Buffer.from(encryptedHex, 'hex')
|
|
const keyBuffer = Buffer.from(key, 'hex').slice(0, KEY_LENGTH)
|
|
|
|
const decipher = crypto.createDecipheriv(ALGORITHM, keyBuffer, iv)
|
|
decipher.setAuthTag(tag)
|
|
|
|
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()])
|
|
return decrypted.toString('utf8')
|
|
} catch (error) {
|
|
throw new Error('Decryption failed: ' + (error as Error).message)
|
|
}
|
|
}
|