如何让Argon2返回固定长度为17字符的哈希值段?
关于Argon2获取固定17字符哈希值的问题
我使用Java的de.mkammerer.argon2库,通过Argon2算法对字符串编码,因需设置固定盐、固定哈希长度等参数,故使用了Argon2的高级接口。目前无法实现获取长度固定为17字符的哈希值段(对应defaultHashLen参数,该参数单位为字节,编码格式为UTF-8)。请问是否有办法强制Argon2返回长度最大为17的编码值?这是否可行?我尝试截取结果,但修改defaultHashLen的值(如17、22)时,每次执行得到的哈希值段完全不同,不清楚原因。
代码示例
import de.mkammerer.argon2.*; import java.util.Base64; public class PasswordArgon2Jvm { private static final int defaultSaltLen = "abcdefghijklmnopqrst".getBytes().length; private static final byte[] saltArray = "abcdefghijklmnopqrst".getBytes(); private static final int defaultHashLen = 17; private static final int iterations = 3; private static final int memory = 1258; private static final int parallelism = 3; public void hashPasswordWithCustomSalt(String pass){ // public static Argon2Advanced createAdvanced(Argon2Factory.Argon2Types type, int defaultSaltLength, int defaultHashLength) { Argon2Advanced argon3 = Argon2Factory.createAdvanced(defaultSaltLen, defaultHashLen); byte[] password = pass.toUpperCase().getBytes(); HashResult hashInBytes = argon3.hashAdvanced(iterations, memory, parallelism, password, saltArray, defaultHashLen, Argon2Version.DEFAULT_VERSION); String hashWithFixedSalt = hashInBytes.getEncoded(); String lastBit = hashWithFixedSalt.substring(hashWithFixedSalt.lastIndexOf("$")+1); System.out.println( pass + " \n" + hashWithFixedSalt + " \n" + lastBit + " \n" + "length: " + lastBit.length() + " \n" + "decoded: " + Base64.getDecoder().decode(lastBit)); } public static void main(String[] args) { PasswordArgon2Jvm pa2jvm = new PasswordArgon2Jvm(); pa2jvm.hashPasswordWithCustomSalt("santiago2"); }
输出结果
santiago2 $argon2i$v=19$m=1258,t=3,p=3$ZFh2dGZIWDRYdGpsV3J0OFh4NEM$2kNm9mxm8XaWcW4KIL+G7Eo 2kNm9mxm8XaWcW4KIL+G7Eo length: 23 decoded: [B@1a86f2f1
问题解答
字节长度与Base64编码长度的混淆:
defaultHashLen指定的是哈希结果的字节长度,而非最终Base64编码后的字符长度。Base64编码规则是每3字节对应4字符,不足部分补位,因此17字节的哈希结果编码后会是23字符(ceil(17*4/3)=23),这是编码机制决定的,Argon2本身无法直接返回17字符的编码值。修改
defaultHashLen导致哈希值变化的原因:不同的defaultHashLen会让Argon2生成不同长度的哈希字节流,算法输出的哈希值本身就会不同,这是正常现象——你要求算法生成不同长度的结果,自然会得到不同的哈希值段。获取最长17字符编码值的可行方案:
- 截取编码结果:先获取指定字节长度的哈希,再对Base64编码后的字符串截取前17字符。但注意:这种操作会损失哈希的熵,增加碰撞风险,不推荐用于密码存储等安全场景。
- 调整哈希字节长度适配Base64:Base64编码后字符长度与字节长度的对应关系是:每3字节对应4字符。若要编码后字符长度≤17,哈希字节长度最大设为12(12字节编码后为16字符);若接受18字符则设为13字节,但无法刚好得到17字符的编码结果(Base64编码长度是4的倍数或补位后的长度,无17字符的情况)。
补充:字节数组打印问题:你输出中的
[B@1a86f2f1是直接打印字节数组对象的内存地址,若要查看字节内容,可改用Arrays.toString(Base64.getDecoder().decode(lastBit))。
内容的提问来源于stack exchange,提问作者Aisatora
相关产品推荐
相关产品推荐

