11.crypto模块
-- 未经授权禁止转载 --
import crypto from 'crypto'

//使用md5算法生成数据的哈希值
const md5 = data => {
    const hash = crypto.createHash("md5") //创建一个md5的哈希对象
    hash.update(data) //更新哈希对象, 处理并传入待哈希的数据
    return hash.digest("hex") //计算哈希值并以十六进制字符串的形式返回
}

//使用sha-1算法生成数据的哈希值
const sha1 = data => {
    const hash = crypto.createHash("sha1")
    hash.update(data)
    return hash.digest("hex")
}

//生成指定长度的随机字符串 - 常用于生成临时密码、令牌等
const randomStr = length => {
    /*
        每个字节在转换为十六进制字符串后会变成两个字符
        所以字节的数量是所需字符串长度的一半(向上取整)
        如:要生成20位的随机字符串,则需要10个字节
    */
    const bytesNeed = Math.ceil(length / 2)
    const randomBytes = crypto.randomBytes(bytesNeed)

    const hexStr = randomBytes.toString('hex') //字节转换成十六进制字符串

    return hexStr.slice(0, length) //截取指定长度的字符串,确保字符串长度符合要求
}

console.log("md5:", md5("dengruicode.com"))
console.log("sha1:", sha1("dengruicode.com"))
console.log("随机字符串:", randomStr(20))

/*
    AES(Advanced Encryption Standard 高级加密标准)
    对称加密算法: 加密和解密使用相同的密钥
*/
//使用AES-GCM模式加密
const aesGcmEncrypt = (plaintext, key) => {  
    //nonce(Number Used Once 一次性使用的数字) 是一个随机字符串 (AES-GCM的nonce长度应为12字节)
    //nonce 用于确保相同的明文也不会产生相同的密文, 从而增强安全性
    const nonce = crypto.randomBytes(12)

    //创建加密器, 使用 aes-256-gcm 算法、给定密钥和nonce
    const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce)

    //使用加密器对明文进行加密, 并将结果转换为十六进制字符串
    let encrypted = cipher.update(plaintext, 'utf8', 'hex')
    encrypted += cipher.final('hex') //加密后的密文数据

    //获取认证标签,并将其转换为十六进制字符串
    //认证标签用于验证数据的完整性和来源的真实性, 防止篡改和假冒
    const authTag = cipher.getAuthTag().toString('hex')

    //将加密后的数据、nonce 和认证标签合并为一个 json 字符串
    const encryptedJson = JSON.stringify({
        nonce: nonce.toString('base64'), //将nonce转换为Base64编码
        encrypted: encrypted,
        authTag: authTag
    })
    return encryptedJson
}

//使用AES-GCM模式解密
const aesGcmDecrypt = (encryptedJson, key) => {
    //从 json 字符串中解析出加密数据、nonce 和认证标签
    const { nonce, encrypted, authTag } = JSON.parse(encryptedJson)

    //将 Base64 编码的 nonce 转换回 Buffer 格式, 以便于解密器使用
    const nonceBuffer = Buffer.from(nonce, 'base64')
    
    //创建解密器, 使用 aes-256-gcm 算法、给定密钥和nonceBuffer
    const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonceBuffer)
    
    //设置解密时用于校验的认证标签
    decipher.setAuthTag(Buffer.from(authTag, 'hex'))
    
    //使用解密器对加密后的数据进行解密, 将十六进制格式的密文转换为 UTF-8 字符串
    let decrypted = decipher.update(encrypted, 'hex', 'utf8')
    decrypted += decipher.final('utf8')

    return decrypted
}

// 密钥长度应为16、24、32字节,对应于AES-128、AES-192、AES-256
const key = crypto.randomBytes(32) // 用于加密和解密的密钥 [生成一个随机的AES-256密钥]
const plaintext = "邓瑞编程" // 要加密的原始文本

const encryptedJson = aesGcmEncrypt(plaintext, key)
const decryptedText = aesGcmDecrypt(encryptedJson, key)

console.log('加密:', encryptedJson)
console.log('解密:', decryptedText)