为什么 crypt/blowfish 使用两种不同的盐生成相同的哈希值?

2023-12-19

这个问题与 PHP 的实现有关crypt() http://php.net/manual/en/function.crypt.php。对于这个问题,salt的前7个字符不算在内,所以一个salt '$2a$07$a' 的长度被认为是 1,因为它只有 1 个盐字符和 7 个元数据字符。

当使用长度超过 22 个字符的 salt 字符串时,生成的哈希值不会发生变化(即截断),并且当使用短于 21 个字符的字符串时,salt 将自动填充(用 '$' 字符,显然);这相当简单。但是,如果给定一个 salt 20 个字符和一个 salt 21 个字符,其中除了 21 长度 salt 的最后一个字符之外,两者相同,则两个哈希字符串将相同。盐长度为 22 个字符,与 21 长度的盐相同,除了最后一个字符之外,散列将再次不同。

代码示例:

$foo = 'bar';
$salt_xx = '$2a$07$';
$salt_19 = $salt_xx . 'b1b2ee48991281a439d';
$salt_20 = $salt_19 . 'a';
$salt_21 = $salt_20 . '2';
$salt_22 = $salt_21 . 'b';

var_dump(
    crypt($foo, $salt_19), 
    crypt($foo, $salt_20), 
    crypt($foo, $salt_21), 
    crypt($foo, $salt_22)
);

将产生:

string(60) "$2a$07$b1b2ee48991281a439d$$.dEUdhUoQXVqUieLTCp0cFVolhFcbuNi"
string(60) "$2a$07$b1b2ee48991281a439da$.UxGYN739wLkV5PGoR1XA4EvNVPjwylG"
string(60) "$2a$07$b1b2ee48991281a439da2.UxGYN739wLkV5PGoR1XA4EvNVPjwylG"
string(60) "$2a$07$b1b2ee48991281a439da2O4AH0.y/AsOuzMpI.f4sBs8E2hQjPUQq"

为什么是这样?

EDIT:

一些用户注意到整个字符串存在差异,这是事实。在salt_20,偏移量 (28, 4) 为da$., 而在salt_21,偏移量 (28, 4) 为da2.;然而,值得注意的是,生成的字符串包括哈希、盐以及生成盐的指令(即$2a$07$);事实上,发生差异的部分仍然是盐。实际的哈希值不变UxGYN739wLkV5PGoR1XA4EvNVPjwylG.

因此,这实际上不是产生的哈希值的差异,而是用于存储哈希值的盐的差异,这正是当前的问题:两个盐生成相同的哈希值。

请记住:输出将采用以下格式:

"$2a$##$saltsaltsaltsaltsaltsaHASHhashHASHhashHASHhashHASHhash"
//                            ^ Hash Starts Here, offset 28,32

其中 ## 是 log-base-2,确定算法运行的迭代次数

Edit 2:

在评论中,要求我发布一些附加信息,因为用户无法重现我的输出。执行以下代码:

var_dump(
    PHP_VERSION, 
    PHP_OS, 
    CRYPT_SALT_LENGTH, 
    CRYPT_STD_DES, 
    CRYPT_EXT_DES, 
    CRYPT_MD5, 
    CRYPT_BLOWFISH
);

产生以下输出:

string(5) "5.3.0"
string(5) "WINNT"
int(60)
int(1)
int(1)
int(1)
int(1)

希望这可以帮助。


经过一些实验,我得出的结论是,这是由于盐的处理方式造成的。 salt 不被视为文字文本,而是被视为 base64 编码的字符串,这样 22 字节的 salt 数据实际上代表一个 16 字节的字符串(floor(22 * 24 / 32) == 16) 盐。 “陷阱!”然而,这个实现的一个问题是,像 Unix crypt 一样,它使用“非标准”base64 字母表。准确地说,它使用这个字母表:

./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$

第 65 个字符,'$', 是填充字符。

现在crypt()函数似乎能够采用小于或等于其最大值的任何长度的盐,并通过丢弃不构成另一个完整字节的任何数据来默默地处理 base64 中的任何不一致。如果您向 crypt 函数传递不属于其 base64 字母表的字符,则 crypt 函数将完全失败,这恰好证实了其操作的理论。

取一个假想的盐'1234'。这与 Base64 完全一致,因为它表示 24 位数据,即 3 个字节,并且不携带任何需要丢弃的数据。这是一种盐,其Len Mod 4为零。将任何字符附加到该盐后,它就会变成 5 个字符的盐,并且Len Mod 4现在是 1。但是,这个附加字符仅代表六位数据,因此无法转换为另一个完整字节,因此将其丢弃。

因此,对于任意两种盐 A 和 B,其中

   Len A Mod 4 == 0 
&& Len B Mod 4 == 1  // these two lines mean the same thing
&& Len B = Len A + 1 // but are semantically important separately
&& A == substr B, 0, Len A

The actual salt used by crypt() to calculate the hash will, in fact, be identical. As proof, I'm including some example PHP code that can be used to show this. The salt constantly rotates in a seminon-random way (based on a randomish segment of the whirlpool hash of the current time to the microsecond), and the data to be hashed (herein called $seed) is simply the current Unix-Epoch time.

$salt = substr(hash('whirlpool',microtime()),rand(0,105),22);
$seed = time();
for ($i = 0, $j = strlen($salt); $i <= $j; ++$i) {
    printf('%02d = %s%s%c',
        $i,
        crypt($seed,'$2a$07$' . substr($salt, 0, $i)),
        $i%4 == 0 || $i % 4 == 1 ? ' <-' : '',
        0x0A
    );
}

这会产生类似于以下内容的输出

00 = $2a$07$$$$$$$$$$$$$$$$$$$$$$.rBxL4x0LvuUp8rhGfnEKSOevBKB5V2. <-
01 = $2a$07$e$$$$$$$$$$$$$$$$$$$$.rBxL4x0LvuUp8rhGfnEKSOevBKB5V2. <-
02 = $2a$07$e8$$$$$$$$$$$$$$$$$$$.WEimjvvOvQ.lGh/V6HFkts7Rq5rpXZG
03 = $2a$07$e89$$$$$$$$$$$$$$$$$$.Ww5p352lsfQCWarRIWWGGbKa074K4/.
04 = $2a$07$e895$$$$$$$$$$$$$$$$$.ZGSPawtL.pOeNI74nhhnHowYrJBrLuW <-
05 = $2a$07$e8955$$$$$$$$$$$$$$$$.ZGSPawtL.pOeNI74nhhnHowYrJBrLuW <-
06 = $2a$07$e8955b$$$$$$$$$$$$$$$.2UumGVfyc4SgAZBs5P6IKlUYma7sxqa
07 = $2a$07$e8955be$$$$$$$$$$$$$$.gb6deOAckxHP/WIZOGPZ6/P3oUSQkPm
08 = $2a$07$e8955be6$$$$$$$$$$$$$.5gox0YOqQMfF6FBU9weAz5RmcIKZoki <-
09 = $2a$07$e8955be61$$$$$$$$$$$$.5gox0YOqQMfF6FBU9weAz5RmcIKZoki <-
10 = $2a$07$e8955be616$$$$$$$$$$$.hWHhdkS9Z3m7/PMKn1Ko7Qf2S7H4ttK
11 = $2a$07$e8955be6162$$$$$$$$$$.meHPOa25CYG2G8JrbC8dPQuWf9yw0Iy
12 = $2a$07$e8955be61624$$$$$$$$$.vcp/UGtAwLJWvtKTndM7w1/30NuYdYa <-
13 = $2a$07$e8955be616246$$$$$$$$.vcp/UGtAwLJWvtKTndM7w1/30NuYdYa <-
14 = $2a$07$e8955be6162468$$$$$$$.OTzcPMwrtXxx6YHKtaX0mypWvqJK5Ye
15 = $2a$07$e8955be6162468d$$$$$$.pDcOFp68WnHqU8tZJxuf2V0nqUqwc0W
16 = $2a$07$e8955be6162468de$$$$$.YDv5tkOeXkOECJmjl1R8zXVRMlU0rJi <-
17 = $2a$07$e8955be6162468deb$$$$.YDv5tkOeXkOECJmjl1R8zXVRMlU0rJi <-
18 = $2a$07$e8955be6162468deb0$$$.aNZIHogUlCn8H7W3naR50pzEsQgnakq
19 = $2a$07$e8955be6162468deb0d$$.ytfAwRL.czZr/K3hGPmbgJlheoZUyL2
20 = $2a$07$e8955be6162468deb0da$.0xhS8VgxJOn4skeI02VNI6jI6324EPe <-
21 = $2a$07$e8955be6162468deb0da3.0xhS8VgxJOn4skeI02VNI6jI6324EPe <-
22 = $2a$07$e8955be6162468deb0da3ucYVpET7X/5YddEeJxVqqUIxs3COrdym

结论?双重。首先,它按预期工作,其次,了解你自己的盐,或者不要自己卷盐。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 crypt/blowfish 使用两种不同的盐生成相同的哈希值? 的相关文章

  • 使用PHP套接字发送和接收数据

    我正在尝试通过 PHP 套接字发送和接收数据 一切正常 但是当我尝试发送数据时 PHP 不发送任何内容 Wireshark 告诉我发送的数据长度为 0 我正在使用这段代码
  • 如何在 HTML / Javascript 页面中插入 PHP 下拉列表

    好吧 这是我的第二篇文章 请接受我是一个完全的新手 愿意学习 花了很多时间在各个网站上寻找答案 而且我几乎已经到达了我需要到达的地方 至少在这一点上 我有一个网页 其中有许多 javascript 函数 这些函数一起使用 google 地图
  • 通过JS Laravel访问存储目录

    有没有办法访问storage目录 该目录已经链接到publicJS 中的目录 我正在尝试制作一个上传图片的表单 验证脚本 if request gt hasFile photos marker gt photos request gt ph
  • 在 Perl 中使用数据引用的正确方法

    我有一组想要处理的数据 为了简化我的代码 最好通过指向原始数据的引用数组来访问我的数据的某些子集 比解释更好的是 我写下了这个例子 它还没有工作 最后 我想更新原始数据 而不必更新所有子集 用 Perl 可以做这样的事情吗 usr bin
  • Azure 上的“phpcomposer.phar install”出现“无法终止进程”错误

    我正在尝试将我的 Symfony 2 应用程序部署到 Microsoft Azure 网站云 为此 我按照本指南中的步骤操作http symfony com doc current cookbook deployment azure web
  • 将数组拆分为特定数量的块

    我知道array chunk 允许将数组拆分为多个块 但块的数量根据元素的数量而变化 我需要的是始终将数组拆分为特定数量的数组 例如 4 个数组 以下代码将数组分为 3 个块 两个块各有 2 个元素 1 个块有 1 个元素 我想要的是将数组
  • 在 PHP 中模拟 jQuery.ajax 请求

    我必须在 PHP 中模拟 AJAX 请求 就像在 jQuery 中一样 我当前的代码在这里 原始 AJAX 调用 不得修改 ajax type POST url someFile php data data success function
  • 文件修改时间检查的成本

    对于Linux下包含少量字节的文件 我只需要处理自上次处理以来发生更改的时间 我通过调用 PHP 检查文件是否被更改clearstatcache filemtime 定期 由于整个文件总是很小 因此删除对 filemtime 的调用并通过将
  • 创建 Facebook 测试用户时访问令牌出现问题

    我正在尝试为我的 Facebook 应用程序创建测试用户 他们在 11 月份的博客文章 http developers facebook com blog post 429 中宣布了此功能 并在此处记录了该功能 http developer
  • PHP使用auto_increment生成短唯一ID?

    我想生成一个简短的 唯一的 ID 而不必检查冲突 我目前正在做类似的事情 但是我当前生成的 ID 是随机的 并且在循环中检查冲突很烦人 并且如果记录数量显着增加 将会变得昂贵 通常担心冲突不是问题 但我想要生成的唯一 ID 是一个由 5 8
  • 选取散列第 N 个元素的最快方法

    我有一个大哈希表 带有字符串索引的数组 并正在寻找一个函数quickly从中选取第一个 理想情况下也是第 N 个 元素 array shift and reset 对于我的需求来说太慢了 UPDATE 我也不是在寻找基于引用的解决方案 该函
  • 如何在 Twitter Card 中传递动态图像路径?

    我在用
  • 如何让Gmail像加载进度条一样

    我想在页面的中心和顶部创建一个像 Gmail 一样的加载进度条 并适用于所有浏览器 这是基本代码
  • PHP:在脚本完成之前获取输出

    我有一个名为 data php 的脚本 如下所示 do some stuff echo result do some other stuff eg database operations 我需要在另一个脚本中使用 data php 的输出
  • 更改API数据输出的布局

    我是 API 集成和 PHP 的新手 我最近将 VIN 解码器集成到我的应用程序中 在输入框中输入车辆的 VIN 选择提交 然后就会显示 API 数据库中有关该车辆的所有信息 数据存储为关联数组 其中包含类别及其相应元素 例如 对于 VIN
  • 监听文件夹和文件(更改)

    可以直接在 PHP 或 Node 上监听文件夹和文件的更改 通过事件 还是我需要创建自己的方法来执行此操作 Example 我需要听文件夹 user 如果我将一些文件添加到该目录中 PHP 或 Node 会收到信息并运行PathEvent
  • HTML 代码中的 PHP [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我用 HTML 代码编写了 PHP div div 但这出现在输出页面中 else print 我怎样才能让PHP执行 你的文件有一个 p
  • PHP 中的多个插入查询[重复]

    这个问题在这里已经有答案了 我正在尝试创建一个 php html 表单 它将结果插入到狗展数据库中 问题是 无论我做什么 我都会收到此错误 查询失败 您的 SQL 语法有错误 检查与您的 MySQL 服务器版本相对应的手册 了解在 INSE
  • 如何在 Carbon Laravel 中添加日期和另一个日期?

    在我的 laravel 项目中 我想将日期时间增加到前一个日期时间 这是我的代码 expire order 0 gt expire date new Carbon now gt addMonths 6 这两行的结果是 2018 01 28
  • 如何在数据列表 HTML PHP 中设置选择

    您好我想知道是否有一种方法可以在数据列表中设置选定的值 我想要这样的东西

随机推荐

  • UITableView 的“反弹区域”中的浅灰色背景

    Apple 的 iPhone 应用程序 例如 Music 和 Contants 使用 UITableView 中的搜索栏 当您向下滚动以使搜索栏向下移动时 滚动视图内容上方的空白区域具有浅灰色背景颜色 请参见屏幕截图 请注意 搜索栏顶部有一
  • 使用 python 在命令行上键入即可完成

    我想用 python 编写一个小型应用程序 目录 文件启动器 为了使其快速 我想自动完成 自动建议条目 但我想显示 这些建议会随着用户的输入而出现 根据我读到的有关 readline 模块完成的内容是 只能使用 完成热键 例如标签 有什么建
  • 快速处理位置权限

    我正在尝试实现一个基本的地图视图并将用户的当前位置作为注释添加到地图中 我已将 requestwheninuse 密钥添加到我的 info plist 并导入 coreLocation 在我的视图控制器的 did load 方法中 我有以下
  • 如何检查自定义模型绑定器内的属性属性

    我想强制系统中的所有日期均有效且不是将来的日期 因此我在自定义模型绑定器中强制执行它们 class DateTimeModelBinder IModelBinder public object BindModel ControllerCon
  • Eclipse 在调试模式下继续部署到设备

    在部署到我的设备一次进行调试后 每次我尝试在常规模式下 运行为 时 它仍然会附加调试器 我已从设备中删除了该应用程序 但它仍然如此 当我只想运行该应用程序而不受笔记本电脑的束缚时 这会导致并出现问题 还有其他人遇到过这个问题吗 如果是这样
  • 创建下拉按钮以根据分类列进行过滤

    我有一个像这样的数据框 import pandas as pd df pd DataFrame df category G1 G1 G1 G1 G1 G1 G1 G2 G2 G2 G2 G2 G2 G2 df date 2012 04 01
  • 如何在 Kotlin 中声明具有两种类型的变量,例如 val x:Int 或 String

    我要写一个像这样的方法 object UIBehavior fun dialog context Context title Int String message Int String val dialogObj AlertDialog B
  • R将多个url放入lapply中

    我有一个字符向量中的 url 列表 我想在 查询 因为如果不是 则 x 查询将被拒绝 urls c url1 url2 url3 这是我想做的 htmlpages lapply urls function x readLines x Sys
  • 当单元格内有文本时如何获得表格单元格的正确高度

    历史 形状大小不等于表格单元格大小并适合形状内的文本 https stackoverflow com questions 63428548 shape size not equal to the table cell size and fi
  • NuGet 不复制配置文件

    我现在尝试了很多不同的事情 但似乎都没有达到预期的效果 我想与我的库共享一个示例配置 或图像或其他 文件 有人可以使用它并从中派生 我尝试默认为只是为了这样做 我尝试通过以下方式将其包含在 nuget 包中 nuspec并通过 csproj
  • C++ 应用程序中的 QML 或反之亦然 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 考虑一个简单的 GUI 显示相当复杂的计算输出的情况 现在我想使用编写一个漂亮的自定义 GUIQML 我还想写我的后台应用程序QT C 我坐在
  • 通过互操作打开文档时如何使 word 可见?

    我想通过互操作打开一个word文档 并且word必须在该过程中可见 它看起来相当简单 因为在word文档的打开函数中有一个名为 visible 的参数 但是word在后台 什么我失踪了吗 static void Main string ar
  • .NET (C#) 中的“StandardIn 尚未重定向”错误

    我想使用标准输入做一个简单的应用程序 我想在一个程序中创建一个列表并在另一个程序中打印它 我想出了以下内容 我不知道 app2 是否有效 但是在 app1 中我收到异常 StandardIn 尚未重定向 在 writeline 上 在 fo
  • 如何修复 WordPress 自定义主题以与插件一起使用?

    这是我第一次尝试编写自定义 WordPress 主题 而且我已经快完成了 与任何事物一样 存在一些错误 但我尝试了几种不同的选项来修复它们 但没有成功 链接为 www studiosimplicit com wp 我的第一个问题是事件页面上
  • 我的对象在 Three.js 中不反射光线

    我在 Three js 场景中有一些基于 CubeGeometry 的网格 它们都反映了我在全局使用的 PointLight 但其中之一 仅用 THREE Geometry 通过代码添加顶点和面 手工 制作的 没有反映出来 即使它没有颜色
  • 使用 openssl C 进行 AES(aes-ige-128、aes-ige-192、aes-ige-256)加密/解密

    最近 我终于 在 stackoverflow 用户 WhozCraig 的帮助下 开始在 CBC 模式下使用 AES 现在 我想做完全相同的事情 但使用 AES IGE 我看了一下openssl 1 0 1e test igetest c并
  • 获取当前页面并移动到Primeng数据表中的特定页面

    我正在使用 primefaces primeNg 的数据表 我可以获取当前所在页面并以编程方式将数据表设置为特定页面吗 我看到数据表使用了分页组件 但是如何使用 ViewChild访问它 任何帮助将不胜感激
  • 在 Objective-C 类中使用时,无法在调试区域中看到 Swift 对象层次结构

    我的问题可能很简单 但我却迷失了方向 任何评论 想法 帮助 预测都会非常有用 这是我的课程 试用SwiftClass swift import Foundation objc public class TrialSwiftClass NSO
  • CAML > 通过 URL 获取项目

    此 CAML 是否可以正常工作 我用 u2u 尝试过 但它不显示 URL 列 我收到此错误 System ApplicationException 一个或多个字段类型未正确安装 请转到列表设置页面删除这些字段
  • 为什么 crypt/blowfish 使用两种不同的盐生成相同的哈希值?

    这个问题与 PHP 的实现有关crypt http php net manual en function crypt php 对于这个问题 salt的前7个字符不算在内 所以一个salt 2a 07 a 的长度被认为是 1 因为它只有 1