1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-06 22:12:47 -05:00

Turn SSH-2 ciphers into a classoid.

This is more or less the same job as the SSH-1 case, only more
extensive, because we have a wider range of ciphers.

I'm a bit disappointed about the AES case, in particular, because I
feel as if it ought to have been possible to arrange to combine this
layer of vtable dispatch with the subsidiary one that selects between
hardware and software implementations of the underlying cipher. I may
come back later and have another try at that, in fact.
This commit is contained in:
Simon Tatham
2018-09-13 14:43:04 +01:00
parent 6c5cc49e27
commit 229af2b5bf
14 changed files with 405 additions and 266 deletions

View File

@ -11,8 +11,7 @@
struct ssh2_bpp_direction {
unsigned long sequence;
const struct ssh2_cipher *cipher;
void *cipher_ctx;
ssh2_cipher *cipher;
const struct ssh_mac *mac;
int etm_mode;
void *mac_ctx;
@ -60,14 +59,14 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
{
struct ssh2_bpp_state *s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
sfree(s->buf);
if (s->out.cipher_ctx)
s->out.cipher->free_context(s->out.cipher_ctx);
if (s->out.cipher)
ssh2_cipher_free(s->out.cipher);
if (s->out.mac_ctx)
s->out.mac->free_context(s->out.mac_ctx);
if (s->out.comp_ctx)
s->out.comp->compress_cleanup(s->out.comp_ctx);
if (s->in.cipher_ctx)
s->in.cipher->free_context(s->in.cipher_ctx);
if (s->in.cipher)
ssh2_cipher_free(s->in.cipher);
if (s->in.mac_ctx)
s->in.mac->free_context(s->in.mac_ctx);
if (s->in.comp_ctx)
@ -79,7 +78,7 @@ static void ssh2_bpp_free(BinaryPacketProtocol *bpp)
void ssh2_bpp_new_outgoing_crypto(
BinaryPacketProtocol *bpp,
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
const struct ssh_compress *compression)
{
@ -87,23 +86,24 @@ void ssh2_bpp_new_outgoing_crypto(
assert(bpp->vt == &ssh2_bpp_vtable);
s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
if (s->out.cipher_ctx)
s->out.cipher->free_context(s->out.cipher_ctx);
if (s->out.cipher)
ssh2_cipher_free(s->out.cipher);
if (s->out.mac_ctx)
s->out.mac->free_context(s->out.mac_ctx);
if (s->out.comp_ctx)
s->out.comp->compress_cleanup(s->out.comp_ctx);
s->out.cipher = cipher;
if (cipher) {
s->out.cipher_ctx = cipher->make_context();
cipher->setkey(s->out.cipher_ctx, ckey);
cipher->setiv(s->out.cipher_ctx, iv);
s->out.cipher = ssh2_cipher_new(cipher);
ssh2_cipher_setkey(s->out.cipher, ckey);
ssh2_cipher_setiv(s->out.cipher, iv);
} else {
s->out.cipher = NULL;
}
s->out.mac = mac;
s->out.etm_mode = etm_mode;
if (mac) {
s->out.mac_ctx = mac->make_context(s->out.cipher_ctx);
s->out.mac_ctx = mac->make_context(s->out.cipher);
mac->setkey(s->out.mac_ctx, mac_key);
}
@ -116,7 +116,7 @@ void ssh2_bpp_new_outgoing_crypto(
void ssh2_bpp_new_incoming_crypto(
BinaryPacketProtocol *bpp,
const struct ssh2_cipher *cipher, const void *ckey, const void *iv,
const struct ssh2_cipheralg *cipher, const void *ckey, const void *iv,
const struct ssh_mac *mac, int etm_mode, const void *mac_key,
const struct ssh_compress *compression)
{
@ -124,23 +124,24 @@ void ssh2_bpp_new_incoming_crypto(
assert(bpp->vt == &ssh2_bpp_vtable);
s = FROMFIELD(bpp, struct ssh2_bpp_state, bpp);
if (s->in.cipher_ctx)
s->in.cipher->free_context(s->in.cipher_ctx);
if (s->in.cipher)
ssh2_cipher_free(s->in.cipher);
if (s->in.mac_ctx)
s->in.mac->free_context(s->in.mac_ctx);
if (s->in.comp_ctx)
s->in.comp->decompress_cleanup(s->in.comp_ctx);
s->in.cipher = cipher;
if (cipher) {
s->in.cipher_ctx = cipher->make_context();
cipher->setkey(s->in.cipher_ctx, ckey);
cipher->setiv(s->in.cipher_ctx, iv);
s->in.cipher = ssh2_cipher_new(cipher);
ssh2_cipher_setkey(s->in.cipher, ckey);
ssh2_cipher_setiv(s->in.cipher, iv);
} else {
s->in.cipher = NULL;
}
s->in.mac = mac;
s->in.etm_mode = etm_mode;
if (mac) {
s->in.mac_ctx = mac->make_context(s->in.cipher_ctx);
s->in.mac_ctx = mac->make_context(s->in.cipher);
mac->setkey(s->in.mac_ctx, mac_key);
}
@ -165,14 +166,15 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->maxlen = 0;
s->length = 0;
if (s->in.cipher)
s->cipherblk = s->in.cipher->blksize;
s->cipherblk = ssh2_cipher_alg(s->in.cipher)->blksize;
else
s->cipherblk = 8;
if (s->cipherblk < 8)
s->cipherblk = 8;
s->maclen = s->in.mac ? s->in.mac->len : 0;
if (s->in.cipher && (s->in.cipher->flags & SSH_CIPHER_IS_CBC) &&
if (s->in.cipher &&
(ssh2_cipher_alg(s->in.cipher)->flags & SSH_CIPHER_IS_CBC) &&
s->in.mac && !s->in.etm_mode) {
/*
* When dealing with a CBC-mode cipher, we want to avoid the
@ -219,9 +221,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->cipherblk));
/* Decrypt one more block (a little further back in
* the stream). */
s->in.cipher->decrypt(
s->in.cipher_ctx,
s->buf + s->packetlen, s->cipherblk);
ssh2_cipher_decrypt(s->in.cipher,
s->buf + s->packetlen, s->cipherblk);
/* Feed that block to the MAC. */
put_data(s->sc_mac_bs,
@ -265,13 +266,13 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->bpp.in_raw, s->buf, 4));
/* Cipher supports length decryption, so do it */
if (s->in.cipher &&
(s->in.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
if (s->in.cipher && (ssh2_cipher_alg(s->in.cipher)->flags &
SSH_CIPHER_SEPARATE_LENGTH)) {
/* Keep the packet the same though, so the MAC passes */
unsigned char len[4];
memcpy(len, s->buf, 4);
s->in.cipher->decrypt_length(
s->in.cipher_ctx, len, 4, s->in.sequence);
ssh2_cipher_decrypt_length(
s->in.cipher, len, 4, s->in.sequence);
s->len = toint(GET_32BIT(len));
} else {
s->len = toint(GET_32BIT(s->buf));
@ -321,8 +322,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
/* Decrypt everything between the length field and the MAC. */
if (s->in.cipher)
s->in.cipher->decrypt(
s->in.cipher_ctx, s->data + 4, s->packetlen - 4);
ssh2_cipher_decrypt(
s->in.cipher, s->data + 4, s->packetlen - 4);
} else {
if (s->bufsize < s->cipherblk) {
s->bufsize = s->cipherblk;
@ -337,8 +338,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
s->bpp.in_raw, s->buf, s->cipherblk));
if (s->in.cipher)
s->in.cipher->decrypt(
s->in.cipher_ctx, s->buf, s->cipherblk);
ssh2_cipher_decrypt(
s->in.cipher, s->buf, s->cipherblk);
/*
* Now get the length figure.
@ -381,8 +382,8 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
/* Decrypt everything _except_ the MAC. */
if (s->in.cipher)
s->in.cipher->decrypt(
s->in.cipher_ctx,
ssh2_cipher_decrypt(
s->in.cipher,
s->data + s->cipherblk, s->packetlen - s->cipherblk);
/*
@ -524,7 +525,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
pkt->downstream_id, pkt->additional_log_text);
}
cipherblk = s->out.cipher ? s->out.cipher->blksize : 8;
cipherblk = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 8;
cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
if (s->out.comp && s->out.comp_ctx) {
@ -573,9 +574,9 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
/* Encrypt length if the scheme requires it */
if (s->out.cipher &&
(s->out.cipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
s->out.cipher->encrypt_length(s->out.cipher_ctx, pkt->data, 4,
s->out.sequence);
(ssh2_cipher_alg(s->out.cipher)->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
ssh2_cipher_encrypt_length(s->out.cipher, pkt->data, 4,
s->out.sequence);
}
put_padding(pkt, maclen, 0);
@ -585,8 +586,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
* OpenSSH-defined encrypt-then-MAC protocol.
*/
if (s->out.cipher)
s->out.cipher->encrypt(s->out.cipher_ctx,
pkt->data + 4, origlen + padding - 4);
ssh2_cipher_encrypt(s->out.cipher,
pkt->data + 4, origlen + padding - 4);
s->out.mac->generate(s->out.mac_ctx, pkt->data, origlen + padding,
s->out.sequence);
} else {
@ -598,8 +599,7 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt)
s->out.mac_ctx, pkt->data, origlen + padding,
s->out.sequence);
if (s->out.cipher)
s->out.cipher->encrypt(s->out.cipher_ctx,
pkt->data, origlen + padding);
ssh2_cipher_encrypt(s->out.cipher, pkt->data, origlen + padding);
}
s->out.sequence++; /* whether or not we MACed */
@ -634,7 +634,7 @@ static void ssh2_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
int block, length;
PktOut *ignore_pkt;
block = s->out.cipher ? s->out.cipher->blksize : 0;
block = s->out.cipher ? ssh2_cipher_alg(s->out.cipher)->blksize : 0;
if (block < 8)
block = 8;
length = pkt->length;