From 97ab28d7499e582c8b8844d5930bb589c536daa5 Mon Sep 17 00:00:00 2001 From: ben Date: Sat, 23 Apr 2005 16:22:51 +0000 Subject: [PATCH] Now that we've got at least some SDCTR modes working (and aes256-ctr is our default preferred cipher), add code to inject SSH_MSG_IGNOREs to randomise the IV when using CBC-mode ciphers. Each cipher has a flag to indicate whether it needs this workaround, and the SSH packet output maze has gained some extra complexity to implement it. git-svn-id: svn://svn.tartarus.org/sgt/putty@5659 cda61777-01e9-0310-a592-d414129be87e --- ssh.c | 35 +++++++++++++++++++++++++++++++---- ssh.h | 2 ++ sshaes.c | 14 +++++++------- ssharcf.c | 4 ++-- sshblowf.c | 4 ++-- sshdes.c | 8 ++++---- 6 files changed, 48 insertions(+), 19 deletions(-) diff --git a/ssh.c b/ssh.c index f26eafd2..0f6793ad 100644 --- a/ssh.c +++ b/ssh.c @@ -1797,8 +1797,19 @@ static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt) * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of * these or get queued, and then when the queue is later emptied * the packets are all passed to defer_noqueue(). + * + * When using a CBC-mode cipher, it's necessary to ensure that an + * attacker can't provide data to be encrypted using an IV that they + * know. We ensure this by prefixing each packet that might contain + * user data with an SSH_MSG_IGNORE. This is done using the deferral + * mechanism, so in this case send_noqueue() ends up redirecting to + * defer_noqueue(). If you don't like this inefficiency, don't use + * CBC. */ +static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int); +static void ssh_pkt_defersend(Ssh); + /* * Send an SSH-2 packet immediately, without queuing or deferring. */ @@ -1806,6 +1817,12 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) { int len; int backlog; + if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { + /* We need to send two packets, so use the deferral mechanism. */ + ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); + ssh_pkt_defersend(ssh); + return; + } len = ssh2_pkt_construct(ssh, pkt); backlog = sk_write(ssh->s, (char *)pkt->data, len); if (backlog > SSH_MAX_BACKLOG) @@ -1823,9 +1840,19 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) /* * Defer an SSH-2 packet. */ -static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore) { - int len = ssh2_pkt_construct(ssh, pkt); + int len; + if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && + ssh->deferred_len == 0 && !noignore) { + /* + * Interpose an SSH_MSG_IGNORE to ensure that user data don't + * get encrypted with a known IV. + */ + struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE); + } + len = ssh2_pkt_construct(ssh, pkt); if (ssh->deferred_len + len > ssh->deferred_size) { ssh->deferred_size = ssh->deferred_len + len + 128; ssh->deferred_send_data = sresize(ssh->deferred_send_data, @@ -1875,7 +1902,7 @@ static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt) if (ssh->queueing) ssh2_pkt_queue(ssh, pkt); else - ssh2_pkt_defer_noqueue(ssh, pkt); + ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); } #endif @@ -1923,7 +1950,7 @@ static void ssh2_pkt_queuesend(Ssh ssh) assert(!ssh->queueing); for (i = 0; i < ssh->queuelen; i++) - ssh2_pkt_defer_noqueue(ssh, ssh->queue[i]); + ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE); ssh->queuelen = 0; ssh_pkt_defersend(ssh); diff --git a/ssh.h b/ssh.h index 87011e97..36924b83 100644 --- a/ssh.h +++ b/ssh.h @@ -154,6 +154,8 @@ struct ssh2_cipher { char *name; int blksize; int keylen; + unsigned int flags; +#define SSH_CIPHER_IS_CBC 1 char *text_name; }; diff --git a/sshaes.c b/sshaes.c index 5664f775..44f8ac59 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1173,49 +1173,49 @@ static const struct ssh2_cipher ssh_aes128_ctr = { aes_make_context, aes_free_context, aes_iv, aes128_key, aes_ssh2_sdctr, aes_ssh2_sdctr, "aes128-ctr", - 16, 128, "AES-128 SDCTR" + 16, 128, 0, "AES-128 SDCTR" }; static const struct ssh2_cipher ssh_aes192_ctr = { aes_make_context, aes_free_context, aes_iv, aes192_key, aes_ssh2_sdctr, aes_ssh2_sdctr, "aes192-ctr", - 16, 192, "AES-192 SDCTR" + 16, 192, 0, "AES-192 SDCTR" }; static const struct ssh2_cipher ssh_aes256_ctr = { aes_make_context, aes_free_context, aes_iv, aes256_key, aes_ssh2_sdctr, aes_ssh2_sdctr, "aes256-ctr", - 16, 256, "AES-256 SDCTR" + 16, 256, 0, "AES-256 SDCTR" }; static const struct ssh2_cipher ssh_aes128 = { aes_make_context, aes_free_context, aes_iv, aes128_key, aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, "aes128-cbc", - 16, 128, "AES-128 CBC" + 16, 128, SSH_CIPHER_IS_CBC, "AES-128 CBC" }; static const struct ssh2_cipher ssh_aes192 = { aes_make_context, aes_free_context, aes_iv, aes192_key, aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, "aes192-cbc", - 16, 192, "AES-192 CBC" + 16, 192, SSH_CIPHER_IS_CBC, "AES-192 CBC" }; static const struct ssh2_cipher ssh_aes256 = { aes_make_context, aes_free_context, aes_iv, aes256_key, aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, "aes256-cbc", - 16, 256, "AES-256 CBC" + 16, 256, SSH_CIPHER_IS_CBC, "AES-256 CBC" }; static const struct ssh2_cipher ssh_rijndael_lysator = { aes_make_context, aes_free_context, aes_iv, aes256_key, aes_ssh2_encrypt_blk, aes_ssh2_decrypt_blk, "rijndael-cbc@lysator.liu.se", - 16, 256, "AES-256 CBC" + 16, 256, SSH_CIPHER_IS_CBC, "AES-256 CBC" }; static const struct ssh2_cipher *const aes_list[] = { diff --git a/ssharcf.c b/ssharcf.c index 2e7287ea..6d4709b4 100644 --- a/ssharcf.c +++ b/ssharcf.c @@ -102,14 +102,14 @@ const struct ssh2_cipher ssh_arcfour128_ssh2 = { arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour128_key, arcfour_block, arcfour_block, "arcfour128-draft-00@putty.projects.tartarus.org", - 1, 128, "Arcfour-128" + 1, 128, 0, "Arcfour-128" }; const struct ssh2_cipher ssh_arcfour256_ssh2 = { arcfour_make_context, arcfour_free_context, arcfour_iv, arcfour256_key, arcfour_block, arcfour_block, "arcfour256-draft-00@putty.projects.tartarus.org", - 1, 256, "Arcfour-256" + 1, 256, 0, "Arcfour-256" }; static const struct ssh2_cipher *const arcfour_list[] = { diff --git a/sshblowf.c b/sshblowf.c index a264c3c5..0ca81eba 100644 --- a/sshblowf.c +++ b/sshblowf.c @@ -573,7 +573,7 @@ static const struct ssh2_cipher ssh_blowfish_ssh2 = { blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish_key, blowfish_ssh2_encrypt_blk, blowfish_ssh2_decrypt_blk, "blowfish-cbc", - 8, 128, "Blowfish-128 CBC" + 8, 128, SSH_CIPHER_IS_CBC, "Blowfish-128 CBC" }; #ifdef ENABLE_BLOWFISH_SSH2_CTR @@ -581,7 +581,7 @@ static const struct ssh2_cipher ssh_blowfish_ssh2_ctr = { blowfish_make_context, blowfish_free_context, blowfish_iv, blowfish256_key, blowfish_ssh2_sdctr, blowfish_ssh2_sdctr, "blowfish-ctr", - 8, 256, "Blowfish-256 SDCTR" + 8, 256, 0, "Blowfish-256 SDCTR" }; #endif diff --git a/sshdes.c b/sshdes.c index 034176ab..833c6897 100644 --- a/sshdes.c +++ b/sshdes.c @@ -965,7 +965,7 @@ static const struct ssh2_cipher ssh_3des_ssh2 = { des3_make_context, des3_free_context, des3_iv, des3_key, des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, "3des-cbc", - 8, 168, "triple-DES CBC" + 8, 168, SSH_CIPHER_IS_CBC, "triple-DES CBC" }; #ifdef ENABLE_3DES_SSH2_CTR @@ -973,7 +973,7 @@ static const struct ssh2_cipher ssh_3des_ssh2_ctr = { des3_make_context, des3_free_context, des3_iv, des3_key, des3_ssh2_sdctr, des3_ssh2_sdctr, "3des-ctr", - 8, 168, "triple-DES SDCTR" + 8, 168, 0, "triple-DES SDCTR" }; #endif @@ -989,14 +989,14 @@ static const struct ssh2_cipher ssh_des_ssh2 = { des_make_context, des3_free_context, des3_iv, des_key, des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, "des-cbc", - 8, 56, "single-DES CBC" + 8, 56, SSH_CIPHER_IS_CBC, "single-DES CBC" }; static const struct ssh2_cipher ssh_des_sshcom_ssh2 = { des_make_context, des3_free_context, des3_iv, des_key, des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, "des-cbc@ssh.com", - 8, 56, "single-DES CBC" + 8, 56, SSH_CIPHER_IS_CBC, "single-DES CBC" }; /* -- 2.11.0