mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-08 08:58:00 +00:00
0d2d20aad0
All the hash-specific state structures, and the functions that directly accessed them, are now local to the source files implementing the hashes themselves. Everywhere we previously used those types or functions, we're now using the standard ssh_hash or ssh2_mac API. The 'simple' functions (hmacmd5_simple, SHA_Simple etc) are now a pair of wrappers in sshauxcrypt.c, each of which takes an algorithm structure and can do the same conceptual thing regardless of what it is.
120 lines
4.0 KiB
C
120 lines
4.0 KiB
C
/*
|
|
* '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])
|
|
{
|
|
unsigned char hashed_salt[64];
|
|
|
|
/* Hash the input salt with the counter value optionally suffixed
|
|
* to get our real 32-byte salt */
|
|
ssh_hash *h = ssh_hash_new(&ssh_sha512);
|
|
put_data(h, salt, saltbytes);
|
|
if (counter)
|
|
put_uint32(h, counter);
|
|
ssh_hash_final(h, hashed_salt);
|
|
|
|
bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output);
|
|
|
|
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 */
|
|
hash_simple(&ssh_sha512, ptrlen_from_asciz(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));
|
|
}
|