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:
92
ssh2bpp.c
92
ssh2bpp.c
@ -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;
|
||||
|
Reference in New Issue
Block a user