You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何生成输入相同输出一致、长度与输入匹配的确定性哈希令牌

问题根源分析
  • 密文过长:你输入的原始令牌是64位十六进制字符串(对应32字节二进制数据),直接将字符串作为明文传入加密函数时,处理的是64字节的UTF-8编码数据,加密后转十六进制输出自然长度翻倍。部分加密实现还会把随机IV拼接到密文前,进一步增加长度。
  • 重启后结果变化:你每次加密都生成随机IV作为参数,AES-CTR模式下IV变化会导致相同明文+相同密钥的加密结果完全不同,容器重启后重新生成IV自然结果无法匹配历史存储值。
可行实现方案

根据你的需求(等长输出、相同输入固定输出、低安全级别要求),推荐两种方案,按需选择:

方案1:HMAC-SHA256(不可逆,适合仅做重复校验场景,优先推荐)

该方案输出刚好是64位十六进制字符串,和你的输入格式、长度完全一致,只要密钥固定,相同输入输出永远相同,性能更高实现更简单。
代码示例:

const { createHmac } = require('crypto');

// 密钥需固定存入环境变量,不要硬编码,容器重启也不会变更
const HMAC_KEY = process.env.TOKEN_HMAC_KEY || '自定义固定密钥字符串';

function generateHashToken(rawToken) {
  return createHmac('sha256', HMAC_KEY)
    .update(rawToken)
    .digest('hex')
    .toUpperCase(); // 如需要和输入一致的全大写格式可保留该行
}

// 测试
const rawToken = '9ECB531EC6AE02CB0274336690E76A0A39511429859537BE242147B65B1824DD';
console.log(generateHashToken(rawToken)); 

优势说明:

  • 输出天然为64位十六进制,和输入长度格式完全匹配
  • 密钥固定的前提下,相同输入100%输出相同结果,不受容器重启影响
  • 带密钥的哈希算法无法反向碰撞出原始令牌,满足非敏感数据保护需求
  • 实现简单,性能远高于对称加密方案

方案2:固定IV的AES-256-CTR(可逆,适合需要还原原始令牌的场景)

如果后续需要从加密结果还原原始令牌,可使用该方案,需注意编码处理保证长度一致。
代码示例:

const { createCipheriv, createDecipheriv, scryptSync } = require('crypto');

// 密钥、IV、盐都固定存入环境变量,不要动态生成
const AES_KEY = scryptSync(process.env.TOKEN_AES_PASSWORD || '自定义固定密码', '固定盐值', 32);
// IV固定为16字节,这里示例用hex字符串转换,可自行替换为你的固定值
const FIXED_IV = Buffer.from(process.env.TOKEN_AES_IV || '0123456789abcdef0123456789abcdef', 'hex');

function encryptToken(rawToken) {
  // 先将输入的hex字符串转为32字节Buffer,不要直接传入UTF-8字符串
  const rawBuffer = Buffer.from(rawToken, 'hex');
  const cipher = createCipheriv('aes-256-ctr', AES_KEY, FIXED_IV);
  const encryptedBuffer = Buffer.concat([cipher.update(rawBuffer), cipher.final()]);
  // 输出转为hex字符串,刚好64位,和输入长度一致
  return encryptedBuffer.toString('hex').toUpperCase();
}

function decryptToken(encryptedToken) {
  const encryptedBuffer = Buffer.from(encryptedToken, 'hex');
  const decipher = createDecipheriv('aes-256-ctr', AES_KEY, FIXED_IV);
  const decryptedBuffer = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]);
  return decryptedBuffer.toString('hex').toUpperCase();
}

注意事项:

  • 绝对不能使用动态生成的随机IV,否则相同输入的加密结果会变化
  • 必须将原始令牌先按hex编码转为Buffer,不能直接传入字符串,否则输出长度会翻倍
注意事项

所有涉及的固定密钥、盐、IV都要存入服务的环境变量配置中,不要硬编码到代码里,既保证配置不会随容器重启变更,也能提升安全性。

内容的提问来源于stack exchange,提问作者Royal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 08:15:03