Java 为什么Spring的BCryptPasswordEncoder为相同的输入生成不同的输出?

Java 为什么Spring的BCryptPasswordEncoder为相同的输入生成不同的输出?,java,spring,spring-security,bcrypt,Java,Spring,Spring Security,Bcrypt,我正在使用Spring security。我的期望是,对于相同的输入,我将始终得到相同的输出。但是对于相同的输入,我得到不同的输出。您可以使用下面的代码段对其进行测试: String password = "123456"; PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String encodedPassword = passwordEncoder.encode(password); System.out.pr

我正在使用Spring security。我的期望是,对于相同的输入,我将始终得到相同的输出。但是对于相同的输入,我得到不同的输出。您可以使用下面的代码段对其进行测试:

String password = "123456"; 
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 
String encodedPassword = passwordEncoder.encode(password);
System.out.print(encodedPassword);
输出:$2a$10$cYLM.QOxpeazcHJ3Oxrlu9SLKB61LHYW5QJ4QKVhemHaxz5QCPI

输出2:$2a$10$KEVYX9YJ0F1X3WL8S.KPUWZSWGYGM9UBI71NOM3ZNBJCWN6AGVW

输出3:$2a$10$nCmrPtUaOLn5EI73VZ4Ouu1TmkSWDUxxD4N6A.8HPWG43VL.RLDC


有人能解释一下为什么BCryptPasswordEncoder会这样吗?

这是完全正常的,因为它使用salt生成密码。你可以阅读“添加”密码和密码背后的想法

这是文档中对
encode
方法的说明

对原始密码进行编码。一般来说,一个好的编码算法应用SHA-1或更大的哈希值与一个8字节或更大的随机生成的salt相结合


生成的密码是咸的,因此不同

请阅读该方法的文档,其中明确说明了密码的安全性。

publicstaticvoidmain(String[]args){
public static void main(String[] args) {
  // spring 4.0.0
  org.springframework.security.crypto.password.PasswordEncoder encoder
   = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();

   // $2a$10$lB6/PKg2/JC4XgdMDXyjs.dLC9jFNAuuNbFkL9udcXe/EBjxSyqxW
   // true
   // $2a$10$KbQiHKTa1WIsQFTQWQKCiujoTJJB7MCMSaSgG/imVkKRicMPwgN5i
   // true
   // $2a$10$5WfW4uxVb4SIdzcTJI9U7eU4ZwaocrvP.2CKkWJkBDKz1dmCh50J2
   // true
   // $2a$10$0wR/6uaPxU7kGyUIsx/JS.krbAA9429fwsuCyTlEFJG54HgdR10nK
   // true
   // $2a$10$gfmnyiTlf8MDmwG7oqKJG.W8rrag8jt6dNW.31ukgr0.quwGujUuO
   // true

    for (int i = 0; i < 5; i++) {
      // "123456" - plain text - user input from user interface
      String passwd = encoder.encode("123456");

      // passwd - password from database
      System.out.println(passwd); // print hash

      // true for all 5 iteration
      System.out.println(encoder.matches("123456", passwd));
    }
}
//spring 4.0.0 org.springframework.security.crypto.password.PasswordEncoder =new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(); //$2a$10$lB6/PKg2/JC4XgdMDXyjs.dlc9jfnaunbfkl9udcxe/EBjxSyqxW //真的 //$2a$10$KBQIHKTA1WISQFTQWQKCIUJOTJJB7MCMSAGG/IMVKRICMPWGN5I //真的 //$2a$10$5WfW4uxVb4SIdzcTJI9U7eU4ZwaocrvP.2CKkWJkBDKz1dmCh50J2 //真的 //$2a$10$0wR/6uaPxU7kGyUIsx/JS.krbAA9429fwsuCyTlEFJG54HgdR10nK //真的 //$2a$10$gfmnyiTlf8MDmwG7oqKJG.W8rrag8jt6dNW.31ukgr0.QUWGUJUO //真的 对于(int i=0;i<5;i++){ //“123456”-纯文本-用户界面的用户输入 字符串passwd=encoder.encode(“123456”); //passwd-来自数据库的密码 System.out.println(passwd);//打印哈希 //所有5次迭代均为true System.out.println(编码器.matches(“123456”,passwd)); } }
第二个$后面的22个字符表示盐值,请参阅。“Salt”是在散列之前添加到密码中的一些随机数据,因此具有给定参数的给定散列算法在大多数情况下会为同一密码生成不同的散列值(防止所谓的彩虹攻击)

让我们剖析原始问题中显示的第一个输出:
$2a$10$cYLM.qoxpeazchj3oxrlu9slkb61lhyw5qj4qkwhemhaxz5qcpi

  • $2a
    :BCrypt算法的标识符
  • $10
    :轮数参数,此处为2^10轮
  • cYLM.qoxpeazchj3oxrlu
    :Salt(128位)
  • 9SLKB61LHYW5QJ4QKVHEMHAXZ5QCPI
    :实际哈希值(184位)
salt和哈希值都使用基数64进行编码

BCrypt输出为: $2a$10$cYLM.QOxpeazcHJ3OXRLU9SLKB61LHYW5QJ4QKVHEMHAXZ5QCPI

$2a$表示哈希算法

10美元是原木轮

下面是经过哈希处理的密码


因为春天会产生不同的盐,所以每次的产量都不一样。您可以引用的BCrypt语法

您能给我一个相同密码的示例吗?@Bhavesh您想实现什么?为什么密码需要相同的哈希值?我想使用bcrpt对spring security执行简单的登录和注册操作。@Bhavesh为此存在方法matches()[.请阅读您想要使用的类的文档。您的措辞让我有点困惑:编码器不生成密码,它生成的代码由salt+哈希密码+其他detalis组成(参见其他答案)。此外:文档(在撰写本文时)是从界面复制的,并且只声明一个好的编码器使用salt。为什么您需要密码具有相同的哈希值?这个问题的最佳答案是:使用您的代码制作一个简单的工具,可能会为一些人节省时间:本例中的名称
passwd
表示encodedPasswor有点违反直觉d(散列码)——不是RAW密码。问题是“有人能解释为什么BCryptPasswordEncoder会这样做吗?”——这个答案没有解释,但只提供代码,没有一个字的解释。