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
bcrypt_setup(const unsigned char * key,int keybytes,const unsigned char * salt,int saltbytes)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
bcrypt_hash(const unsigned char * key,int keybytes,const unsigned char * salt,int saltbytes,unsigned char output[32])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
bcrypt_genblock(int counter,const unsigned char hashed_passphrase[64],const unsigned char * salt,int saltbytes,unsigned char output[32])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 unsigned char hashed_salt[64];
58
59 /* Hash the input salt with the counter value optionally suffixed
60 * to get our real 32-byte salt */
61 ssh_hash *h = ssh_hash_new(&ssh_sha512);
62 put_data(h, salt, saltbytes);
63 if (counter)
64 put_uint32(h, counter);
65 ssh_hash_final(h, hashed_salt);
66
67 bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output);
68
69 smemclr(&hashed_salt, sizeof(hashed_salt));
70 }
71
openssh_bcrypt(const char * passphrase,const unsigned char * salt,int saltbytes,int rounds,unsigned char * out,int outbytes)72 void openssh_bcrypt(const char *passphrase,
73 const unsigned char *salt, int saltbytes,
74 int rounds, unsigned char *out, int outbytes)
75 {
76 unsigned char hashed_passphrase[64];
77 unsigned char block[32], outblock[32];
78 const unsigned char *thissalt;
79 int thissaltbytes;
80 int modulus, residue, i, j, round;
81
82 /* Hash the passphrase to get the bcrypt key material */
83 hash_simple(&ssh_sha512, ptrlen_from_asciz(passphrase), hashed_passphrase);
84
85 /* We output key bytes in a scattered fashion to meld all output
86 * key blocks into all parts of the output. To do this, we pick a
87 * modulus, and we output the key bytes to indices of out[] in the
88 * following order: first the indices that are multiples of the
89 * modulus, then the ones congruent to 1 mod modulus, etc. Each of
90 * those passes consumes exactly one block output from
91 * bcrypt_genblock, so we must pick a modulus large enough that at
92 * most 32 bytes are used in the pass. */
93 modulus = (outbytes + 31) / 32;
94
95 for (residue = 0; residue < modulus; residue++) {
96 /* Our output block of data is the XOR of all blocks generated
97 * by bcrypt in the following loop */
98 memset(outblock, 0, sizeof(outblock));
99
100 thissalt = salt;
101 thissaltbytes = saltbytes;
102 for (round = 0; round < rounds; round++) {
103 bcrypt_genblock(round == 0 ? residue+1 : 0,
104 hashed_passphrase,
105 thissalt, thissaltbytes, block);
106 /* Each subsequent bcrypt call reuses the previous one's
107 * output as its salt */
108 thissalt = block;
109 thissaltbytes = 32;
110
111 for (i = 0; i < 32; i++)
112 outblock[i] ^= block[i];
113 }
114
115 for (i = residue, j = 0; i < outbytes; i += modulus, j++)
116 out[i] = outblock[j];
117 }
118 smemclr(&hashed_passphrase, sizeof(hashed_passphrase));
119 }
120