Java 如何解析Spring Security散列的密码哈希?

Java 如何解析Spring Security散列的密码哈希?,java,spring,spring-security,password-hash,Java,Spring,Spring Security,Password Hash,我想将用户从应用程序迁移到外部SSO。我希望我的用户保留他们现有的密码,因此我希望检索哈希密码并将其提供给SSO应用程序。该算法在两侧都是相同的(pbkdf2-sha256),因此应该可以工作 因此,我需要能够从数据库中的条目中检索salt和hash密码 我的应用程序使用Spring安全性 似乎我需要手动执行此操作,因为Pbkdf2PasswordEncoder实现的接口PasswordEncoder没有提供从存储值检索初始元素的方法 实现这一目标的正确方法是什么 谢谢 编辑: 这是我的密码 P

我想将用户从应用程序迁移到外部SSO。我希望我的用户保留他们现有的密码,因此我希望检索哈希密码并将其提供给SSO应用程序。该算法在两侧都是相同的(pbkdf2-sha256),因此应该可以工作

因此,我需要能够从数据库中的条目中检索salt和hash密码

我的应用程序使用Spring安全性

似乎我需要手动执行此操作,因为Pbkdf2PasswordEncoder实现的接口PasswordEncoder没有提供从存储值检索初始元素的方法

实现这一目标的正确方法是什么

谢谢

编辑:

这是我的密码

Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder("", 27500, 512);
String encoded = encoder.encode("password");
System.out.println(encoded); // prints the hex encoded hashed password: 2a319aaf0252d77e671cf1b074f149f7eed1b362afb47bef84e9b01a8140b26a733cd22df007d68668915c7bd51af9eefda1662216a184fa7eb034c176ce9518fc83f3fd935a2d3d
final byte[] digested = Hex.decode(encoded);
byte[] salt = EncodingUtils.subArray(digested, 0, 7);
byte[] password = EncodingUtils.subArray(digested, 8, digested.length);
System.out.println(new String(Base64.getEncoder().encode(salt))); // prints KjGarwJS134=
System.out.println(new String(Base64.getEncoder().encode(password))); // prints HPGwdPFJ9+7Rs2KvtHvvhOmwGoFAsmpzPNIt8AfWhmiRXHvVGvnu/aFmIhahhPp+sDTBds6VGPyD8/2TWi09
如果我随后转到并输入以下值:

  • 主密码:密码
  • 盐:KjGarwJS134=
  • 迭代次数:27500
  • 丹麦克伦:512
  • PBE密码:sha256

然后,我希望输出与我的代码的最后一次输出匹配,但事实并非如此。

您显然无法从散列中获取密码,但我认为您不是在问这个问题。以下是您将如何做到这一点:

  • 首先检查它是否为base64。如果是这样,请将字符串和base64解码,将其转换为字节数组。(默认值仅为十六进制半字节,即选项2)
  • 如果不是,那就是六角咬。你可以告诉我;如果整个东西只由数字和字母a-f组成,那么它是这个,否则它是#1(base64)。将十六进制半字节解析回字节数组相当简单;通过parseInt每隔2个字符抛出一次:
    Integer.parseInt(in.substring(x,x+2),0x10)-末尾的0x10很重要
  • 用这个方法获得的字节数组是salt和哈希,按顺序连接。默认情况下,salt将是8个字节,但这在spring中都是可配置的。所以,去掉数组中的前8个字节-这是你的重点
  • 剩下的只是原始散列

  • @弗拉基米尔:我认为他们想要访问原始散列(但加密)密码位。然后将该信息传输到新的SSO服务(这意味着用户不必更改密码)。Vladimir,GhostCat是对的,我只需要将原始密码复制到一个新软件,该软件以不同的方式存储它(base64 vs hex,等等),但使用相同的哈希算法。所以基本上我需要从存储的条目中检索salt。@sroup我猜在线工具有问题/不同之处。我尝试了你的代码,使用salt和密码生成了一个新的散列,结果是相同的。所以盐是正确的。尽管如此,我还是设置了
    encoder.setAlgorithm(SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA256)以使用您想要的算法。我没有更改默认配置,因此它实际上是8字节和十六进制半字节。但是我没有使用你描述的算法来解码它。我使用的是org.springframework.security.Hex.decode(),这似乎就是SpringSecurity所使用的。你能详细说明一下吗?在
    x中什么是
    ?Hex.decode应该也可以in'是从数据库中获取的字符串。x是索引。Hex.encode只是将字节序列0xAA 0x9F转换为字符串“AA9F”。Hex.decode撤销该操作;Hex.decode的源代码将执行类似以下操作:
    byte[]decode(String in){byte[]out=new byte[in.length()/2];for(int i=0;i
    那么我想我的代码中有一个bug,因为我使用了你的算法和这个解码函数,但它不起作用。我将添加一段代码,向您展示我在做什么。您是否确认,一旦我获得了salt和密码,如果我对它们进行base64编码,并将密码和base64 salt提供给例如,那么我应该获得base64密码,前提是我输入相同的选项?@sroup-不,您无法从哈希中获取密码,这就是哈希的要点拿盐,用盐和密码(把密码发送到一个你无法控制的网站是……好吧,这会让我皮肤发痒)用PBKDF2-SHA256生成散列。然后,salt+散列应该与应用我的算法得到的结果相匹配。要么是你把事情弄糊涂了,要么是你把事情弄糊涂了。哈希不是密码。不可能从“散列”返回到“密码”,这就是它们的全部意义。除非你解开你脑子里的这个烂摊子,否则你不会明白这一点。