1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Turn SSH-1 ciphers into a classoid.

The interchangeable system of SSH-1 ciphers previously followed the
same pattern as the backends and the public-key algorithms, in that
all the clients would maintain two separate pointers, one to the
vtable and the other to the individual instance / context. Now I've
merged them, just as I did with those other two, so that you only cart
around a single pointer, which has a vtable pointer inside it and a
type distinguishing it from an instance of any of the other
interchangeable sets of algorithms.
This commit is contained in:
Simon Tatham 2018-09-13 13:29:32 +01:00
parent 65b65bb8ef
commit 6c5cc49e27
6 changed files with 139 additions and 86 deletions

7
ssh.c
View File

@ -2914,10 +2914,9 @@ static void do_ssh1_login(void *vctx)
sfree(s->rsabuf);
{
const struct ssh_cipher *cipher =
(s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 :
s->cipher_type == SSH_CIPHER_DES ? &ssh_des :
&ssh_3des);
const struct ssh1_cipheralg *cipher =
(s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh1_blowfish :
s->cipher_type == SSH_CIPHER_DES ? &ssh1_des : &ssh1_3des);
ssh1_bpp_new_cipher(ssh->bpp, cipher, ssh->session_key);
logeventf(ssh, "Initialised %s encryption", cipher->text_name);
}

30
ssh.h
View File

@ -420,17 +420,27 @@ void SHA384_Init(SHA384_State * s);
void SHA384_Final(SHA384_State * s, unsigned char *output);
void SHA384_Simple(const void *p, int len, unsigned char *output);
struct ssh_mac;
struct ssh_cipher {
void *(*make_context)(void);
void (*free_context)(void *);
void (*sesskey) (void *, const void *key); /* for SSH-1 */
void (*encrypt) (void *, void *blk, int len);
void (*decrypt) (void *, void *blk, int len);
struct ssh2_macalg;
struct ssh1_cipheralg;
typedef const struct ssh1_cipheralg *ssh1_cipher;
struct ssh1_cipheralg {
ssh1_cipher *(*new)(void);
void (*free)(ssh1_cipher *);
void (*sesskey)(ssh1_cipher *, const void *key);
void (*encrypt)(ssh1_cipher *, void *blk, int len);
void (*decrypt)(ssh1_cipher *, void *blk, int len);
int blksize;
const char *text_name;
};
#define ssh1_cipher_new(alg) ((alg)->new())
#define ssh1_cipher_free(ctx) ((*(ctx))->free(ctx))
#define ssh1_cipher_sesskey(ctx, key) ((*(ctx))->sesskey(ctx, key))
#define ssh1_cipher_encrypt(ctx, blk, len) ((*(ctx))->encrypt(ctx, blk, len))
#define ssh1_cipher_decrypt(ctx, blk, len) ((*(ctx))->decrypt(ctx, blk, len))
struct ssh2_cipher {
void *(*make_context)(void);
void (*free_context)(void *);
@ -576,9 +586,9 @@ struct ssh2_userkey {
/* The maximum length of any hash algorithm used in kex. (bytes) */
#define SSH2_KEX_MAX_HASH_LEN (64) /* SHA-512 */
extern const struct ssh_cipher ssh_3des;
extern const struct ssh_cipher ssh_des;
extern const struct ssh_cipher ssh_blowfish_ssh1;
extern const struct ssh1_cipheralg ssh1_3des;
extern const struct ssh1_cipheralg ssh1_des;
extern const struct ssh1_cipheralg ssh1_blowfish;
extern const struct ssh2_ciphers ssh2_3des;
extern const struct ssh2_ciphers ssh2_des;
extern const struct ssh2_ciphers ssh2_aes;

View File

@ -17,8 +17,7 @@ struct ssh1_bpp_state {
int chunk;
PktIn *pktin;
const struct ssh_cipher *cipher;
void *cipher_ctx;
ssh1_cipher *cipher;
struct crcda_ctx *crcda_ctx;
@ -51,7 +50,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
{
struct ssh1_bpp_state *s = FROMFIELD(bpp, struct ssh1_bpp_state, bpp);
if (s->cipher)
s->cipher->free_context(s->cipher_ctx);
ssh1_cipher_free(s->cipher);
if (s->compctx)
zlib_compress_cleanup(s->compctx);
if (s->decompctx)
@ -64,7 +63,7 @@ static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
}
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
const struct ssh_cipher *cipher,
const struct ssh1_cipheralg *cipher,
const void *session_key)
{
struct ssh1_bpp_state *s;
@ -73,10 +72,9 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
assert(!s->cipher);
s->cipher = cipher;
if (s->cipher) {
s->cipher_ctx = cipher->make_context();
cipher->sesskey(s->cipher_ctx, session_key);
if (cipher) {
s->cipher = ssh1_cipher_new(cipher);
ssh1_cipher_sesskey(s->cipher, session_key);
assert(!s->crcda_ctx);
s->crcda_ctx = crcda_make_context();
@ -146,7 +144,7 @@ static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
}
if (s->cipher)
s->cipher->decrypt(s->cipher_ctx, s->data, s->biglen);
ssh1_cipher_decrypt(s->cipher, s->data, s->biglen);
s->realcrc = crc32_compute(s->data, s->biglen - 4);
s->gotcrc = GET_32BIT(s->data + s->biglen - 4);
@ -273,7 +271,7 @@ static void ssh1_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
PUT_32BIT(pkt->data + pktoffs, len);
if (s->cipher)
s->cipher->encrypt(s->cipher_ctx, pkt->data + pktoffs + 4, biglen);
ssh1_cipher_encrypt(s->cipher, pkt->data + pktoffs + 4, biglen);
bufchain_add(s->bpp.out_raw, pkt->data + pktoffs,
biglen + 4); /* len(length+padding+type+data+CRC) */

View File

@ -561,17 +561,32 @@ void *blowfish_make_context(void)
return snew(BlowfishContext);
}
static void *blowfish_ssh1_make_context(void)
{
/* In SSH-1, need one key for each direction */
return snewn(2, BlowfishContext);
}
void blowfish_free_context(void *handle)
{
sfree(handle);
}
struct blowfish_ssh1_ctx {
/* In SSH-1, need one key for each direction */
BlowfishContext contexts[2];
ssh1_cipher vt;
};
static ssh1_cipher *blowfish_ssh1_new(void)
{
struct blowfish_ssh1_ctx *ctx = snew(struct blowfish_ssh1_ctx);
ctx->vt = &ssh1_blowfish;
return &ctx->vt;
}
static void blowfish_ssh1_free(ssh1_cipher *cipher)
{
struct blowfish_ssh1_ctx *ctx =
FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt);
smemclr(ctx, sizeof(*ctx));
sfree(ctx);
}
static void blowfish_key(void *handle, const void *key)
{
BlowfishContext *ctx = (BlowfishContext *)handle;
@ -592,25 +607,27 @@ static void blowfish_iv(void *handle, const void *viv)
ctx->iv1 = GET_32BIT_MSB_FIRST(iv + 4);
}
static void blowfish_sesskey(void *handle, const void *key)
static void blowfish_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
{
BlowfishContext *ctx = (BlowfishContext *)handle;
blowfish_setkey(ctx, key, SSH_SESSION_KEY_LENGTH);
ctx->iv0 = 0;
ctx->iv1 = 0;
ctx[1] = ctx[0]; /* structure copy */
struct blowfish_ssh1_ctx *ctx =
FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt);
blowfish_setkey(&ctx->contexts[0], key, SSH_SESSION_KEY_LENGTH);
ctx->contexts[0].iv0 = ctx->contexts[0].iv1 = 0;
ctx->contexts[1] = ctx->contexts[0]; /* structure copy */
}
static void blowfish_ssh1_encrypt_blk(void *handle, void *blk, int len)
static void blowfish_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
BlowfishContext *ctx = (BlowfishContext *)handle;
blowfish_lsb_encrypt_cbc(blk, len, ctx);
struct blowfish_ssh1_ctx *ctx =
FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt);
blowfish_lsb_encrypt_cbc(blk, len, ctx->contexts);
}
static void blowfish_ssh1_decrypt_blk(void *handle, void *blk, int len)
static void blowfish_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
BlowfishContext *ctx = (BlowfishContext *)handle;
blowfish_lsb_decrypt_cbc(blk, len, ctx+1);
struct blowfish_ssh1_ctx *ctx =
FROMFIELD(cipher, struct blowfish_ssh1_ctx, vt);
blowfish_lsb_decrypt_cbc(blk, len, ctx->contexts+1);
}
static void blowfish_ssh2_encrypt_blk(void *handle, void *blk, int len)
@ -631,8 +648,9 @@ static void blowfish_ssh2_sdctr(void *handle, void *blk, int len)
blowfish_msb_sdctr(blk, len, ctx);
}
const struct ssh_cipher ssh_blowfish_ssh1 = {
blowfish_ssh1_make_context, blowfish_free_context, blowfish_sesskey,
const struct ssh1_cipheralg ssh1_blowfish = {
blowfish_ssh1_new, blowfish_ssh1_free,
blowfish_ssh1_sesskey,
blowfish_ssh1_encrypt_blk, blowfish_ssh1_decrypt_blk,
8, "Blowfish-128 CBC"
};

View File

@ -32,7 +32,7 @@ struct BinaryPacketProtocol {
BinaryPacketProtocol *ssh1_bpp_new(void);
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
const struct ssh_cipher *cipher,
const struct ssh1_cipheralg *cipher,
const void *session_key);
void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp);

110
sshdes.c
View File

@ -752,10 +752,23 @@ static void *des3_make_context(void)
return snewn(3, DESContext);
}
static void *des3_ssh1_make_context(void)
struct des3_ssh1_ctx {
/* 3 cipher context for each direction */
DESContext contexts[6];
ssh1_cipher vt;
};
struct des_ssh1_ctx {
/* 1 cipher context for each direction */
DESContext contexts[2];
ssh1_cipher vt;
};
static ssh1_cipher *des3_ssh1_new(void)
{
/* Need 3 keys for each direction, in SSH-1 */
return snewn(6, DESContext);
struct des3_ssh1_ctx *ctx = snew(struct des3_ssh1_ctx);
ctx->vt = &ssh1_3des;
return &ctx->vt;
}
static void *des_make_context(void)
@ -763,10 +776,25 @@ static void *des_make_context(void)
return snew(DESContext);
}
static void *des_ssh1_make_context(void)
static ssh1_cipher *des_ssh1_new(void)
{
/* Need one key for each direction, in SSH-1 */
return snewn(2, DESContext);
struct des_ssh1_ctx *ctx = snew(struct des_ssh1_ctx);
ctx->vt = &ssh1_des;
return &ctx->vt;
}
static void des3_ssh1_free(ssh1_cipher *cipher)
{
struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt);
smemclr(ctx, sizeof(*ctx));
sfree(ctx);
}
static void des_ssh1_free(ssh1_cipher *cipher)
{
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
smemclr(ctx, sizeof(*ctx));
sfree(ctx);
}
static void des3_free_context(void *handle) /* used for both 3DES and DES */
@ -802,23 +830,42 @@ static void des_key(void *handle, const void *vkey)
GET_32BIT_MSB_FIRST(key + 4), &keys[0]);
}
static void des3_sesskey(void *handle, const void *key)
static void des3_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
{
DESContext *keys = (DESContext *) handle;
des3_key(keys, key);
des3_key(keys+3, key);
struct des3_ssh1_ctx *ctx = FROMFIELD(cipher, struct des3_ssh1_ctx, vt);
des3_key(ctx->contexts, key);
des3_key(ctx->contexts+3, key);
}
static void des3_encrypt_blk(void *handle, void *blk, int len)
static void des3_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
DESContext *keys = (DESContext *) handle;
des_3cbc_encrypt(blk, len, keys);
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
des_3cbc_encrypt(blk, len, ctx->contexts);
}
static void des3_decrypt_blk(void *handle, void *blk, int len)
static void des3_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
DESContext *keys = (DESContext *) handle;
des_3cbc_decrypt(blk, len, keys+3);
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
des_3cbc_decrypt(blk, len, ctx->contexts+3);
}
static void des_ssh1_sesskey(ssh1_cipher *cipher, const void *key)
{
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
des_key(ctx->contexts, key);
des_key(ctx->contexts+1, key);
}
static void des_ssh1_encrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
des_cbc_encrypt(blk, len, ctx->contexts);
}
static void des_ssh1_decrypt_blk(ssh1_cipher *cipher, void *blk, int len)
{
struct des_ssh1_ctx *ctx = FROMFIELD(cipher, struct des_ssh1_ctx, vt);
des_cbc_decrypt(blk, len, ctx->contexts+1);
}
static void des3_ssh2_encrypt_blk(void *handle, void *blk, int len)
@ -1017,34 +1064,15 @@ const struct ssh2_ciphers ssh2_des = {
des_list
};
const struct ssh_cipher ssh_3des = {
des3_ssh1_make_context, des3_free_context, des3_sesskey,
des3_encrypt_blk, des3_decrypt_blk,
const struct ssh1_cipheralg ssh1_3des = {
des3_ssh1_new, des3_ssh1_free, des3_ssh1_sesskey,
des3_ssh1_encrypt_blk, des3_ssh1_decrypt_blk,
8, "triple-DES inner-CBC"
};
static void des_sesskey(void *handle, const void *key)
{
DESContext *keys = (DESContext *) handle;
des_key(keys, key);
des_key(keys+1, key);
}
static void des_encrypt_blk(void *handle, void *blk, int len)
{
DESContext *keys = (DESContext *) handle;
des_cbc_encrypt(blk, len, keys);
}
static void des_decrypt_blk(void *handle, void *blk, int len)
{
DESContext *keys = (DESContext *) handle;
des_cbc_decrypt(blk, len, keys+1);
}
const struct ssh_cipher ssh_des = {
des_ssh1_make_context, des3_free_context, des_sesskey,
des_encrypt_blk, des_decrypt_blk,
const struct ssh1_cipheralg ssh1_des = {
des_ssh1_new, des_ssh1_free, des_ssh1_sesskey,
des_ssh1_encrypt_blk, des_ssh1_decrypt_blk,
8, "single-DES CBC"
};