Now that we've got at least some SDCTR modes working (and aes256-ctr is our
authorben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 23 Apr 2005 16:22:51 +0000 (16:22 +0000)
committerben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 23 Apr 2005 16:22:51 +0000 (16:22 +0000)
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
ssh.h
sshaes.c
ssharcf.c
sshblowf.c
sshdes.c

diff --git a/ssh.c b/ssh.c
index f26eafd..0f6793a 100644 (file)
--- 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 87011e9..36924b8 100644 (file)
--- 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;
 };
 
index 5664f77..44f8ac5 100644 (file)
--- 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[] = {
index 2e7287e..6d4709b 100644 (file)
--- 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[] = {
index a264c3c..0ca81eb 100644 (file)
@@ -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
 
index 034176a..833c689 100644 (file)
--- 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"
 };
 
 /*