Skip to content

Commit d637528

Browse files
committed
Implementation of OpenSSH's bcrypt.
This isn't the same as the standard bcrypt; it's OpenSSH's modification that they use for their new-style key format. In order to implement this, I've broken up blowfish_setkey() into two subfunctions, and provided one of them with an extra optional salt parameter, which is NULL in ordinary Blowfish but used by bcrypt. Also, I've exposed some of sshblowf.c's internal machinery for the new sshbcrypt.c to use.
1 parent a8658ed commit d637528

File tree

4 files changed

+213
-15
lines changed

4 files changed

+213
-15
lines changed

ssh.h

+4
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ void des_encrypt_xdmauth(const unsigned char *key,
663663
void des_decrypt_xdmauth(const unsigned char *key,
664664
unsigned char *blk, int len);
665665

666+
void openssh_bcrypt(const char *passphrase,
667+
const unsigned char *salt, int saltbytes,
668+
int rounds, unsigned char *out, int outbytes);
669+
666670
/*
667671
* For progress updates in the key generation utility.
668672
*/

sshbcrypt.c

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* 'bcrypt' password hash function, for PuTTY's import/export of
3+
* OpenSSH encrypted private key files.
4+
*
5+
* This is not really the same as the original bcrypt; OpenSSH has
6+
* modified it in various ways, and of course we have to do the same.
7+
*/
8+
9+
#include <stddef.h>
10+
#include <string.h>
11+
#include "ssh.h"
12+
#include "sshblowf.h"
13+
14+
BlowfishContext *bcrypt_setup(const unsigned char *key, int keybytes,
15+
const unsigned char *salt, int saltbytes)
16+
{
17+
int i;
18+
BlowfishContext *ctx;
19+
20+
ctx = blowfish_make_context();
21+
blowfish_initkey(ctx);
22+
blowfish_expandkey(ctx, key, keybytes, salt, saltbytes);
23+
24+
/* Original bcrypt replaces this fixed loop count with the
25+
* variable cost. OpenSSH instead iterates the whole thing more
26+
* than once if it wants extra rounds. */
27+
for (i = 0; i < 64; i++) {
28+
blowfish_expandkey(ctx, salt, saltbytes, NULL, 0);
29+
blowfish_expandkey(ctx, key, keybytes, NULL, 0);
30+
}
31+
32+
return ctx;
33+
}
34+
35+
void bcrypt_hash(const unsigned char *key, int keybytes,
36+
const unsigned char *salt, int saltbytes,
37+
unsigned char output[32])
38+
{
39+
BlowfishContext *ctx;
40+
int i;
41+
42+
ctx = bcrypt_setup(key, keybytes, salt, saltbytes);
43+
/* This was quite a nice starting string until it ran into
44+
* little-endian Blowfish :-/ */
45+
memcpy(output, "cyxOmorhcitawolBhsiftawSanyDetim", 32);
46+
for (i = 0; i < 64; i++) {
47+
blowfish_lsb_encrypt_ecb(output, 32, ctx);
48+
}
49+
blowfish_free_context(ctx);
50+
}
51+
52+
void bcrypt_genblock(int counter,
53+
const unsigned char hashed_passphrase[64],
54+
const unsigned char *salt, int saltbytes,
55+
unsigned char output[32])
56+
{
57+
SHA512_State shastate;
58+
unsigned char hashed_salt[64];
59+
unsigned char countbuf[4];
60+
61+
/* Hash the input salt with the counter value optionally suffixed
62+
* to get our real 32-byte salt */
63+
SHA512_Init(&shastate);
64+
SHA512_Bytes(&shastate, salt, saltbytes);
65+
if (counter) {
66+
PUT_32BIT_MSB_FIRST(countbuf, counter);
67+
SHA512_Bytes(&shastate, countbuf, 4);
68+
}
69+
SHA512_Final(&shastate, hashed_salt);
70+
71+
bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output);
72+
73+
smemclr(&shastate, sizeof(shastate));
74+
smemclr(&hashed_salt, sizeof(hashed_salt));
75+
}
76+
77+
void openssh_bcrypt(const char *passphrase,
78+
const unsigned char *salt, int saltbytes,
79+
int rounds, unsigned char *out, int outbytes)
80+
{
81+
unsigned char hashed_passphrase[64];
82+
unsigned char block[32], outblock[32];
83+
const unsigned char *thissalt;
84+
int thissaltbytes;
85+
int modulus, residue, i, j, round;
86+
87+
/* Hash the passphrase to get the bcrypt key material */
88+
SHA512_Simple(passphrase, strlen(passphrase), hashed_passphrase);
89+
90+
/* We output key bytes in a scattered fashion to meld all output
91+
* key blocks into all parts of the output. To do this, we pick a
92+
* modulus, and we output the key bytes to indices of out[] in the
93+
* following order: first the indices that are multiples of the
94+
* modulus, then the ones congruent to 1 mod modulus, etc. Each of
95+
* those passes consumes exactly one block output from
96+
* bcrypt_genblock, so we must pick a modulus large enough that at
97+
* most 32 bytes are used in the pass. */
98+
modulus = (outbytes + 31) / 32;
99+
100+
for (residue = 0; residue < modulus; residue++) {
101+
/* Our output block of data is the XOR of all blocks generated
102+
* by bcrypt in the following loop */
103+
memset(outblock, 0, sizeof(outblock));
104+
105+
thissalt = salt;
106+
thissaltbytes = saltbytes;
107+
for (round = 0; round < rounds; round++) {
108+
bcrypt_genblock(round == 0 ? residue+1 : 0,
109+
hashed_passphrase,
110+
thissalt, thissaltbytes, block);
111+
/* Each subsequent bcrypt call reuses the previous one's
112+
* output as its salt */
113+
thissalt = block;
114+
thissaltbytes = 32;
115+
116+
for (i = 0; i < 32; i++)
117+
outblock[i] ^= block[i];
118+
}
119+
120+
for (i = residue, j = 0; i < outbytes; i += modulus, j++)
121+
out[i] = outblock[j];
122+
}
123+
smemclr(&hashed_passphrase, sizeof(hashed_passphrase));
124+
}

sshblowf.c

+70-15
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
#include <assert.h>
88
#include <stdio.h>
99
#include "ssh.h"
10+
#include "sshblowf.h"
1011

11-
typedef struct {
12+
struct BlowfishContext {
1213
word32 S0[256], S1[256], S2[256], S3[256], P[18];
1314
word32 iv0, iv1; /* for CBC mode */
14-
} BlowfishContext;
15+
};
1516

1617
/*
1718
* The Blowfish init data: hex digits of the fractional part of pi.
@@ -305,6 +306,24 @@ static void blowfish_lsb_encrypt_cbc(unsigned char *blk, int len,
305306
ctx->iv1 = iv1;
306307
}
307308

309+
void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len,
310+
BlowfishContext * ctx)
311+
{
312+
word32 xL, xR, out[2];
313+
314+
assert((len & 7) == 0);
315+
316+
while (len > 0) {
317+
xL = GET_32BIT_LSB_FIRST(blk);
318+
xR = GET_32BIT_LSB_FIRST(blk + 4);
319+
blowfish_encrypt(xL, xR, out, ctx);
320+
PUT_32BIT_LSB_FIRST(blk, out[0]);
321+
PUT_32BIT_LSB_FIRST(blk + 4, out[1]);
322+
blk += 8;
323+
len -= 8;
324+
}
325+
}
326+
308327
static void blowfish_lsb_decrypt_cbc(unsigned char *blk, int len,
309328
BlowfishContext * ctx)
310329
{
@@ -415,19 +434,44 @@ static void blowfish_msb_sdctr(unsigned char *blk, int len,
415434
ctx->iv1 = iv1;
416435
}
417436

418-
static void blowfish_setkey(BlowfishContext * ctx,
419-
const unsigned char *key, short keybytes)
437+
void blowfish_initkey(BlowfishContext *ctx)
438+
{
439+
int i;
440+
441+
for (i = 0; i < 18; i++) {
442+
ctx->P[i] = parray[i];
443+
}
444+
445+
for (i = 0; i < 256; i++) {
446+
ctx->S0[i] = sbox0[i];
447+
ctx->S1[i] = sbox1[i];
448+
ctx->S2[i] = sbox2[i];
449+
ctx->S3[i] = sbox3[i];
450+
}
451+
}
452+
453+
void blowfish_expandkey(BlowfishContext * ctx,
454+
const unsigned char *key, short keybytes,
455+
const unsigned char *salt, short saltbytes)
420456
{
421457
word32 *S0 = ctx->S0;
422458
word32 *S1 = ctx->S1;
423459
word32 *S2 = ctx->S2;
424460
word32 *S3 = ctx->S3;
425461
word32 *P = ctx->P;
426462
word32 str[2];
427-
int i;
463+
int i, j;
464+
int saltpos;
465+
unsigned char dummysalt[1];
466+
467+
saltpos = 0;
468+
if (!salt) {
469+
saltbytes = 1;
470+
salt = dummysalt;
471+
dummysalt[0] = 0;
472+
}
428473

429474
for (i = 0; i < 18; i++) {
430-
P[i] = parray[i];
431475
P[i] ^=
432476
((word32) (unsigned char) (key[(i * 4 + 0) % keybytes])) << 24;
433477
P[i] ^=
@@ -437,48 +481,59 @@ static void blowfish_setkey(BlowfishContext * ctx,
437481
P[i] ^= ((word32) (unsigned char) (key[(i * 4 + 3) % keybytes]));
438482
}
439483

440-
for (i = 0; i < 256; i++) {
441-
S0[i] = sbox0[i];
442-
S1[i] = sbox1[i];
443-
S2[i] = sbox2[i];
444-
S3[i] = sbox3[i];
445-
}
446-
447484
str[0] = str[1] = 0;
448485

449486
for (i = 0; i < 18; i += 2) {
487+
for (j = 0; j < 8; j++)
488+
str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4));
489+
450490
blowfish_encrypt(str[0], str[1], str, ctx);
451491
P[i] = str[0];
452492
P[i + 1] = str[1];
453493
}
454494

455495
for (i = 0; i < 256; i += 2) {
496+
for (j = 0; j < 8; j++)
497+
str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4));
456498
blowfish_encrypt(str[0], str[1], str, ctx);
457499
S0[i] = str[0];
458500
S0[i + 1] = str[1];
459501
}
460502
for (i = 0; i < 256; i += 2) {
503+
for (j = 0; j < 8; j++)
504+
str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4));
461505
blowfish_encrypt(str[0], str[1], str, ctx);
462506
S1[i] = str[0];
463507
S1[i + 1] = str[1];
464508
}
465509
for (i = 0; i < 256; i += 2) {
510+
for (j = 0; j < 8; j++)
511+
str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4));
466512
blowfish_encrypt(str[0], str[1], str, ctx);
467513
S2[i] = str[0];
468514
S2[i + 1] = str[1];
469515
}
470516
for (i = 0; i < 256; i += 2) {
517+
for (j = 0; j < 8; j++)
518+
str[j/4] ^= ((word32)salt[saltpos++ % saltbytes]) << (24-8*(j%4));
471519
blowfish_encrypt(str[0], str[1], str, ctx);
472520
S3[i] = str[0];
473521
S3[i + 1] = str[1];
474522
}
475523
}
476524

525+
static void blowfish_setkey(BlowfishContext *ctx,
526+
const unsigned char *key, short keybytes)
527+
{
528+
blowfish_initkey(ctx);
529+
blowfish_expandkey(ctx, key, keybytes, NULL, 0);
530+
}
531+
477532
/* -- Interface with PuTTY -- */
478533

479534
#define SSH_SESSION_KEY_LENGTH 32
480535

481-
static void *blowfish_make_context(void)
536+
void *blowfish_make_context(void)
482537
{
483538
return snew(BlowfishContext);
484539
}
@@ -489,7 +544,7 @@ static void *blowfish_ssh1_make_context(void)
489544
return snewn(2, BlowfishContext);
490545
}
491546

492-
static void blowfish_free_context(void *handle)
547+
void blowfish_free_context(void *handle)
493548
{
494549
sfree(handle);
495550
}

sshblowf.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Header file shared between sshblowf.c and sshbcrypt.c. Exposes the
3+
* internal Blowfish routines needed by bcrypt.
4+
*/
5+
6+
typedef struct BlowfishContext BlowfishContext;
7+
8+
void *blowfish_make_context(void);
9+
void blowfish_free_context(void *handle);
10+
void blowfish_initkey(BlowfishContext *ctx);
11+
void blowfish_expandkey(BlowfishContext *ctx,
12+
const unsigned char *key, short keybytes,
13+
const unsigned char *salt, short saltbytes);
14+
void blowfish_lsb_encrypt_ecb(unsigned char *blk, int len,
15+
BlowfishContext *ctx);

0 commit comments

Comments
 (0)