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