# 简介

bcrypt函数是OpenBSD和其他系统包括一些Linux发行版（如SUSE Linux）的默认密码哈希算法。

# bcrypt算法实现

Function bcrypt
Input:
cost:     Number (4..31)                      log2(Iterations). e.g. 12 ==> 212 = 4,096 iterations
salt:     array of Bytes (16 bytes)           random salt
Output:
hash:     array of Bytes (24 bytes)

//Initialize Blowfish state with expensive key setup algorithm
//P: array of 18 subkeys (UInt32[18])
//S: Four substitution boxes (S-boxes), S0...S3. Each S-box is 1,024 bytes (UInt32[256])
P, S <- EksBlowfishSetup(cost, salt, password)

//Repeatedly encrypt the text "OrpheanBeholderScryDoubt" 64 times
ctext <- "OrpheanBeholderScryDoubt"  //24 bytes ==> three 64-bit blocks
repeat (64)
ctext <-  EncryptECB(P, S, ctext) //encrypt using standard Blowfish in ECB mode

//24-byte ctext is resulting password hash
return Concatenate(cost, salt, ctext)


salt 是加密用盐，用来混淆密码使用。

Function EksBlowfishSetup
Input:
salt:     array of Bytes (16 bytes)      random salt
cost:     Number (4..31)                 log2(Iterations). e.g. 12 ==> 212 = 4,096 iterations
Output:
P:        array of UInt32                array of 18 per-round subkeys
S1..S4:   array of UInt32                array of four SBoxes; each SBox is 256 UInt32 (i.e. 1024 KB)

//Initialize P (Subkeys), and S (Substitution boxes) with the hex digits of pi
P, S  <- InitialState()

//Permutate P and S based on the password and salt
P, S  <- ExpandKey(P, S, salt, password)

//This is the "Expensive" part of the "Expensive Key Setup".
//Otherwise the key setup is identical to Blowfish.
repeat (2cost)
P, S  <-  ExpandKey(P, S, 0, password)
P, S  <- ExpandKey(P, S, 0, salt)

return P, S


Function ExpandKey
Input:
salt:     Byte[16]                      random salt
P:        array of UInt32               Array of 18 subkeys
S1..S4:   UInt32[1024]                  Four 1 KB SBoxes
Output:
P:        array of UInt32               Array of 18 per-round subkeys
S1..S4:   UInt32[1024]                  Four 1 KB SBoxes

//Mix password into the P subkeys array
for n   <- 1 to 18 do

//Treat the 128-bit salt as two 64-bit halves (the Blowfish block size).
saltHalf[0]   <-  salt[0..63]  //Lower 64-bits of salt
saltHalf[1]   <-  salt[64..127]  //Upper 64-bits of salt

//Initialize an 8-byte (64-bit) buffer with all zeros.
block   <-  0

//Mix internal state into P-boxes
for n   <-  1 to 9 do
//xor 64-bit block with a 64-bit salt half
block   <-  block xor saltHalf[(n-1) mod 2] //each iteration alternating between saltHalf[0], and saltHalf[1]

//encrypt block using current key schedule
block   <-  Encrypt(P, S, block)
P2n   <-  block[0..31]      //lower 32-bits of block
P2n+1   <- block[32..63]  //upper 32-bits block

//Mix encrypted state into the internal S-boxes of state
for i   <- 1 to 4 do
for n   <- 0 to 127 do
block   <- Encrypt(state, block xor salt[64(n-1)..64n-1]) //as above
Si[2n]     <- block[0..31]  //lower 32-bits
Si[2n+1]   <-  block[32..63]  //upper 32-bits
return state


ExpandKey主要用来生成P和S，算法的生成比较复杂，大家感兴趣的可以详细研究一下。

# bcrypt hash的结构

$2b$[cost]$[22 character salt][31 character hash]  比如： $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
\__/\/ \____________________/\_____________________________/
Alg Cost      Salt                        Hash


10 表示的是代价因子，这里是2的10次方，也就是1024轮。

N9qo8uLOickgx2ZMRZoMye 是16个字节（128bits）的salt经过base64编码得到的22长度的字符。

## hash的历史

• $1$: MD5-based crypt ('md5crypt')
• $2$: Blowfish-based crypt ('bcrypt')
• $sha1$: SHA-1-based crypt ('sha1crypt')
• $5$: SHA-256-based crypt ('sha256crypt')
• $6$: SHA-512-based crypt ('sha512crypt')

• String 必须是UTF-8编码
• 必须包含null终止符

posted @ 2021-09-16 10:19  flydean  阅读(16206)  评论(1编辑  收藏  举报