зеркало из https://github.com/github/putty.git
125 строки
4.2 KiB
C
125 строки
4.2 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])
|
|
{
|
|
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));
|
|
}
|