Bcrypt
翁子皓 2016 / 6 / 2
Design
- key-dependent S-box
- highly complex key schedule
- pre-process about 4 KB of text
Limit
Bcrypt has P-box and S-boxes with about 4 KB of size,
constantly accessed and modified throughout the algorithm.
To run Bcrypt on GPU, each core will have to store it in the GPU main RAM. They will compete for usage of the memory bus. So Bcrypt can't run on GPU with full parallelism.
Format
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
$2a$ : Bcrypt 10 : rounds
N9qo... : base64 encoded salt
IjZAg... : base64 encoded hash
2^{10}
210
Algorithm
Blowfish
Uses 1 P-box and 4 S-boxes each round
re-calculates P-box and S-box each round
typedef struct {
unsigned int pbox[256];
unsigned int sbox[4][256];
} blowfish_context_t;
void encryptblock(blowfish_context_t *ctx, unsigned int *hi, unsigned int *lo)
{
int i, temp;
for(i = 0; i < 16; i++) {
*hi ^= ctx->pbox[i];
*lo ^= BLOWFISH_F(*hi);
temp = *hi, *hi = *lo, *lo = temp;
}
temp = *hi, *hi = *lo, *lo = temp;
*lo ^= ctx->pbox[16];
*hi ^= ctx->pbox[17];
}
#define BLOWFISH_F(x) \
(((ctx->sbox[0][x >> 24] + \
ctx->sbox[1][(x >> 16) & 0xFF]) ^ \
ctx->sbox[2][(x >> 8) & 0xFF]) + \
ctx->sbox[3][x & 0xFF])
Initalize
void initiate(blowfish_context_t *ctx, unsigned char *key)
{
// first initialize pbox, sbox from PI
int i, j, k;
for(i = 0, j = 0; i < 18; i++) {
//XOR P with key treating the key as cyclic
ctx->pbox[i] ^= key;
}
unsigned int hi = 0, lo = 0;
for(i = 0; i < 18; i += 2) {
blowfish_encryptblock(ctx, &hi, &lo);
ctx->pbox[i] = hi;
ctx->pbox[i + 1] = lo;
}
for(i = 0; i < 4; i++) {
for(j = 0; j < 256; j += 2) {
blowfish_encryptblock(ctx, &hi, &lo);
ctx->sbox[i][j] = hi;
ctx->sbox[i][j + 1] = lo;
}
}
}
Bcrypt
bcrypt(round, salt, input)
state = EksBlowfishSetup(round, salt, input)
ctext = "OrpheanBeholderScryDoubt"
repeat (64)
ctext = EncryptECB(state, ctext)
return Concatenate(round, salt, ctext)
Overview
EksBlowfishSetup(round, salt, key)
state = InitState()
state = ExpandKey(state, salt, key)
repeat (1 << round)
state = ExpandKey(state, 0, key)
state = ExpandKey(state, 0, salt)
return state
EksBlowfishSetup
expensive key schedule Blowfish
ExpandKey(state, salt, key)
for(n = 1..18)
Pn = key ^ Pn //treat the key as cyclic
ctext = Encrypt(salt[0..63])
P1 = ctext[0..31]
P2 = ctext[32..63]
for(n = 2..9)
//encrypt using the current key schedule and treat the salt as cyclic
ctext = Encrypt(ctext ^ salt)
P2n-1 = ctext[0..31]
P2n = ctext[32..63]
for(i = 1..4)
for(n = 0..127)
ctext = Encrypt(ctext ^ salt)
Si[2n] = ctext[0..31]
Si[2n+1] = ctext[32..63]
return state
ExpandKey
Modified Blowfish key schedule
Concatenate(round, salt, ctext)
// base64_encode(salt): 22 chars
// base64_encode(ctext): 31 chars
// total: 60 chars
return "$2a$" + base64_encode(salt) + base64_encode(ctext)
Concatenate
Put everything together
Bcrypt
By Gordon Ueng
Bcrypt
- 820