Skip to content

bcryptUtil

工具类

ts
// src/utils/bcryptUtil.ts
import bcrypt from 'bcryptjs'

const saltRounds = 10
// $2a$10$K06X0zR9/K6xe2qKT1IqXO(盐值) + vPOyank6cYHv4iWjS8U5Ail/XfY5mEy哈希值
// 盐值是一串随机生成的字符串,它会被加入明文密码中一起进行哈希,从而增强密码的安全性
// 不是加密它,而是参与加密的“调料”。
// 假设你有两个用户都设置了相同的密码 123456
// bcrypt 自动会把盐值“夹带”进最终哈希中,所以你不需要单独存储它,验证时它会自动提取出来
// 盐值是一段“额外随机信息”,参与加密,防止同样的密码生成同样的哈希,从而提升安全性
export class BcryptUtil {
    /**
     * 加密明文密码
     */
    static async hashPassword(plainText: string): Promise<string> {
        const salt = await bcrypt.genSalt(saltRounds)
        return bcrypt.hash(plainText, salt)
    }

    /**
     * 使用指定盐生成特定 hash(可复现)
     */
    static hashWithSalt(plainText: string, salt: string): string {
        return bcrypt.hashSync(plainText, salt)
    }

    /**
     * 验证密码是否匹配 hash 自动盐值
     */
    static async comparePassword(plainText: string, hash: string): Promise<boolean> {
        return bcrypt.compare(plainText, hash)
    }
}

使用

ts
// 加密
const password = ref('123.com')
const hashed = ref('')
const isMatch = ref()
const salt = ref('$2a$10$K06X0zR9/K6xe2qKT1IqXO')
// $2b$10$c5RoTi6l96QX5lvODvAYEOrZbs/RGxEQWKXbxhkc.cMw.d0FWyxje
// $2a$10$K06X0zR9/K6xe2qKT1IqXOvPOyank6cYHv4iWjS8U5Ail/XfY5mEy
// $2a$10$K06X0zR9/K6xe2qKT1IqXOvPOyank6cYHv4iWjS8U5Ail/XfY5mEy

// 指定盐值 生成Hash
const generateHash = async () => {
    hashed.value = await BcryptUtil.hashWithSalt(password.value,salt.value)
    console.log("hashed.value",hashed.value)
}
// 明文和hash值是否匹配
const checkPassword = async () => {
    if (!hashed.value) return
    isMatch.value = await BcryptUtil.comparePassword(password.value, hashed.value)
    console.log(isMatch.value)
}
onMounted(async() => {
    await generateHash()
    checkPassword()

})

加密

ts
import crypto from 'crypto'

const key = crypto.createHash('sha256').update('fixed_secret_key').digest() // 32字节密钥
const iv = Buffer.alloc(16, 0) // 初始向量(示例)

function encrypt(text: string) {
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv)
  let encrypted = cipher.update(text, 'utf8', 'hex')
  encrypted += cipher.final('hex')
  return encrypted
}

function decrypt(encrypted: string) {
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
  let decrypted = decipher.update(encrypted, 'hex', 'utf8')
  decrypted += decipher.final('utf8')
  return decrypted
}

const encrypted = encrypt('123.com')
console.log('加密:', encrypted)
console.log('解密:', decrypt(encrypted))
ts
bcrypt 是哈希算法,不是加密算法,不能用密钥解密。
bcrypt 只能单向哈希,无法解密。
如果需要“密钥”控制加密,应该用对称加密算法(如 AES)或者基于密钥的哈希(HMAC)等。
ts
哈希算法(Hash Algorithm)是一种单向散列函数,它将任意长度的输入数据通过计算,映射成固定长度的输出(称为哈希值、摘要、散列值),而且具有以下几个核心特性

单向性(不可逆)
从输入计算出哈希值非常容易,但从哈希值“反向推算”原始输入几乎不可能。

所以哈希算法不是“加密算法”,它不支持解密。

2. 固定长度输出
无论输入数据大小是多少,输出的哈希值长度是固定的,比如:

MD5 输出 128 位(16 字节)

SHA-256 输出 256 位(32 字节)

bcrypt 输出 60 字符的字符串(经过编码)

3. 碰撞阻力
两个不同的输入数据产生相同哈希值(碰撞)的概率非常低。

4. 雪崩效应
输入哪怕有一点点变化,输出的哈希值也会发生巨大变化。

哈希算法和加密算法

ts
MD5	128 位	校验文件完整性(已不安全)
SHA-1	160 位	版本控制、数字签名(逐渐被弃用)
SHA-256	256 位	安全加密、数字签名、区块链等
bcrypt	192 位(经编码)	密码哈希(内含盐值和成本因子)

哈希算法不是加密算法,不能解密,只能验证数据是否一致。

bcrypt 是一种加盐哈希算法,专门用于密码存储,防止暴力破解。

哈希算法 vs 加密算法

特点哈希算法加密算法
方向单向(不可逆)双向(可加密和解密)
目的验证数据完整性、认证密码等数据保密,信息传输安全
典型算法SHA-256、MD5、bcryptAES、RSA、DES、ChaCha20