source: filezilla/trunk/fuentes/src/putty/sshbcrypt.c @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 4.2 KB
Line 
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
14BlowfishContext *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
35void 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
52void 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
77void 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}
Note: See TracBrowser for help on using the repository browser.