Bcrypt分步操作

2020-08-28 23:06:00

BCRYPT是一个密钥派生函数,它可以被认为是一个慢速哈希函数。其目的是将一段输入数据慢慢转换为固定大小、确定性和不可预测的输出。一种常见的用例是将密码转换为n位密钥,然后可以使用该密钥进行安全身份验证。

在Qvault这里,我们在安全系统中使用bcrypt。Bcrypt是一种非常流行的密码散列函数,以至于我们目前在实用密码学课程中讲授的散列函数。

该输出可用于与未来的散列进行比较,以查看原始数据是否匹配。

在Web开发中,以明文形式存储用户密码是不安全的。如果攻击者获得访问服务器数据库的权限,他们可以找到原始的电子邮件/密码组合,并利用它们攻击其他站点上的相同用户。

至少我们必须散列用户的密码,但是像SHA-2和MD5这样的散列函数太快而不安全。使用像bcrypt这样的KDF提供了比快速散列更安全的好处,因为它计算昂贵且速度慢。如果攻击者获得了使用快速算法生成的密码散列数据库的访问权限,那么他们很容易通过猜测不同的输入并查看输出是否匹配来“反转”散列。

例如,假设攻击者在数据库中找到以下条目:

密码password3产生了匹配的散列!现在攻击者知道[email protected]可能会在其他站点上使用密码password3,可以侵入其他帐户。这是可能的,因为攻击者能够每秒快速计算许多散列并猜测数百万个潜在密码。

Func bcrypt(COST INT,SALT[16]字节,PASSWORD[72]字节)(散列字符串){//使用昂贵的密钥设置算法初始化Blowfish状态//这是算法pEighteSubkey,sFourSubBox:=expensveBlowfish Setup(COST,SALT,PASSWORD)的较慢部分//重复加密文本";OrpheanBeholderScrypDoubt";64次//24字节=3个64位。I++{//在ECB模式下使用标准Blowfish加密ctext=cryptECB(pEighteSubkey,sFourSubBox,ctext)}//以正确的格式返回版本、成本、盐和ctext";$2a${成本}${salt}{ctext}";}

如您所见,bcrypt在很大程度上依赖于Blowfish密码。简而言之,bcrypt是一种昂贵的密钥扩展,再加上Blowfish加密。

//pEighteSubKey:18个子密钥数组//sFourSubBox:4个替换框//每个S-Box是uint32func expensveBlowfish Setup(COST INT,SALT[16]字节,Password[72]字节)(pEighteSubkey[18]uint32,SFourSubBox[4][256]uint32){//初始化数组pEighteSubkey:=[18]uint32 sFourSubBox:=[4][256]uint32//使用pi的十六进制数字填充pEighteSubkey和sFourSubBox//此初始状态的工作方式与原始Blowfish算法相同//它使用十六进制的小数部分pi填充P数组和S-box条目。昂贵的&34;昂贵密钥设置的一部分//否则密钥设置将与Blowfish相同//根据i:=0;i<;math.Pow(2,Cost);i++{pEighteSubkey,sFourSubBox=expandKey(pEighteSubkey,sFourSubBox,0,Password)的成本因子,将密钥扩展成指数级//。pE8teenSubkey.Pow(2,Cost);i++{pEighteSubkey,sFourSubBox=expandKey(pEighteSubkey,sFourSubBox,0,Password)。

根据COST参数的值,expandKey函数的执行次数呈指数级增加。ExpandKey函数由以下伪代码解释:

Func expandKey(pE18teenSubkey[18]uint32,sFourSubBoxs[4][256]uint32,salt[16]字节,password[72]byte)(pEighteSubkey[18]uint32,sFourSubBox[4][256]uint32){//将密码与i:=0;i<;18;I++{//将密码视为循环密码,将32位密码块与子键pEighteSubkey[i]^=password[I%18]}//将128位SALT视为两个64位部分saltHalf[0]=saltHalf[0:63]saltHalf[1]=SALT[64:127]//使用全零初始化8字节(64位)缓冲区。BLOCK:=[8]BYTE//将内部状态混合到I:=0;I<;9的P盒中;I++{//XOR 64位块和64位半盐//每次迭代在saltHalf[0]和saltHalf[1]BLOCK^=saltHalf[(i-1)mod 2]之间交替//使用当前密钥计划加密块BLOWFISH BLOCK=ENCRYPT(pEighteenSubkey,sFourSubBox,BLOCK)//拆分块并用作新的子密钥pEighteSubkey[2*i]=BLOCK[0。I<;4;i++{for j:=0;j<;127;j++{//使用Blowfish块加密加密块//其中sal[i]是64位块block=crypt(pEighteSubkey,sFourSubBox,block^salt[i])sFourSubBox[2*i]=block[0:31]sFourSubBox[2*i+1]=block[32:63]}}返回p。

它帮助我通过使用更“真实”的编程语法(如GO)来可视化伪代码的细节。如果这对您没有帮助,那么请看一下这里的维基百科页面上的代码。