Implement my experimental arcfour modes. The 256-bit version is disabled
authorben <ben@cda61777-01e9-0310-a592-d414129be87e>
Thu, 14 Apr 2005 22:58:29 +0000 (22:58 +0000)
committerben <ben@cda61777-01e9-0310-a592-d414129be87e>
Thu, 14 Apr 2005 22:58:29 +0000 (22:58 +0000)
until I can test it against someone else's implementation.

git-svn-id: svn://svn.tartarus.org/sgt/putty@5633 cda61777-01e9-0310-a592-d414129be87e

Recipe
config.c
doc/config.but
doc/errors.but
doc/index.but
putty.h
settings.c
ssh.c
ssh.h
ssharcf.c [new file with mode: 0644]

diff --git a/Recipe b/Recipe
index 4c8a059..f0facd6 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -205,7 +205,7 @@ NONSSH   = telnet raw rlogin ldisc pinger
 # SSH back end (putty, plink, pscp, psftp).
 SSH      = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf
          + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd
-         + sshaes sshsh512 sshbn wildcard pinger
+         + sshaes sshsh512 sshbn wildcard pinger ssharcf
 WINSSH   = SSH winnoise winpgntc
 UXSSH    = SSH uxnoise uxagentc
 MACSSH   = SSH macnoise
index 8a47195..638e3d8 100644 (file)
--- a/config.c
+++ b/config.c
@@ -120,6 +120,7 @@ static void cipherlist_handler(union control *ctrl, void *dlg,
            { "Blowfish",               CIPHER_BLOWFISH },
            { "DES",                    CIPHER_DES },
            { "AES (SSH-2 only)",       CIPHER_AES },
+           { "Arcfour (SSH-2 only)",   CIPHER_ARCFOUR },
            { "-- warn below here --",  CIPHER_WARN }
        };
 
index bd92b96..72fd59f 100644 (file)
@@ -2127,6 +2127,8 @@ PuTTY currently supports the following algorithms:
 
 \b \i{AES} (Rijndael) - 256, 192, or 128-bit CBC (SSH-2 only)
 
+\b \i{Arcfour} (RC4) - 256 or 128-bit stream cipher (SSH-2 only)
+
 \b \i{Blowfish} - 128-bit CBC
 
 \b \ii{Triple-DES} - 168-bit CBC
index bc352ce..f3fa117 100644 (file)
@@ -74,7 +74,7 @@ this, let us know and we'll move it up our priority list.
 
 This occurs when the SSH server does not offer any ciphers which you
 have configured PuTTY to consider strong enough. By default, PuTTY
-puts up this warning only for \ii{single-DES} encryption.
+puts up this warning only for \ii{single-DES} and \i{Arcfour} encryption.
 
 See \k{config-ssh-encryption} for more information on this message.
 
index 963eed1..ba01c8f 100644 (file)
@@ -595,6 +595,9 @@ saved sessions from
 \IM{AES} Advanced Encryption Standard
 \IM{AES} Rijndael
 
+\IM{Arcfour} Arcfour
+\IM{Arcfour} RC4
+
 \IM{triple-DES} triple-DES
 
 \IM{single-DES} single-DES
diff --git a/putty.h b/putty.h
index fd8e13d..b08eec8 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -261,6 +261,7 @@ enum {
     CIPHER_BLOWFISH,
     CIPHER_AES,                               /* (SSH-2 only) */
     CIPHER_DES,
+    CIPHER_ARCFOUR,
     CIPHER_MAX                        /* no. ciphers (inc warn) */
 };
 
index 11efd75..9dce4f8 100644 (file)
@@ -18,6 +18,7 @@ static const struct keyval ciphernames[] = {
     { "blowfish",   CIPHER_BLOWFISH },
     { "3des",      CIPHER_3DES },
     { "WARN",      CIPHER_WARN },
+    { "arcfour",    CIPHER_ARCFOUR },
     { "des",       CIPHER_DES }
 };
 
diff --git a/ssh.c b/ssh.c
index b5f34a5..8c7f775 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -4915,6 +4915,9 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
              case CIPHER_AES:
                s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes;
                break;
+             case CIPHER_ARCFOUR:
+               s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour;
+               break;
              case CIPHER_WARN:
                /* Flag for later. Don't bother if it's the last in
                 * the list. */
diff --git a/ssh.h b/ssh.h
index bf1ba48..87011e9 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -233,6 +233,7 @@ extern const struct ssh2_ciphers ssh2_3des;
 extern const struct ssh2_ciphers ssh2_des;
 extern const struct ssh2_ciphers ssh2_aes;
 extern const struct ssh2_ciphers ssh2_blowfish;
+extern const struct ssh2_ciphers ssh2_arcfour;
 extern const struct ssh_kex ssh_diffiehellman_group1;
 extern const struct ssh_kex ssh_diffiehellman_group14;
 extern const struct ssh_kex ssh_diffiehellman_gex;
diff --git a/ssharcf.c b/ssharcf.c
new file mode 100644 (file)
index 0000000..5946488
--- /dev/null
+++ b/ssharcf.c
@@ -0,0 +1,127 @@
+/*
+ * Arcfour (RC4) implementation for PuTTY.
+ *
+ * Coded from Schneier.
+ */
+
+#include <assert.h>
+#include "ssh.h"
+
+typedef struct {
+    unsigned char i, j, s[256];
+} ArcfourContext;
+
+static void arcfour_block(void *handle, unsigned char *blk, int len)
+{
+    ArcfourContext *ctx = (ArcfourContext *)handle;
+    unsigned k;
+    unsigned char tmp, i, j, *s;
+
+    s = ctx->s;
+    i = ctx->i; j = ctx->j;
+    for (k = 0; k < len; k++) {
+       i  = (i + 1) & 0xff;
+       j  = (j + s[i]) & 0xff;
+       tmp = s[i]; s[i] = s[j]; s[j] = tmp;
+       blk[k] ^= s[(s[i]+s[j]) & 0xff];
+    }
+    ctx->i = i; ctx->j = j;
+}
+
+static void arcfour_setkey(ArcfourContext *ctx, unsigned char const *key,
+                          unsigned keybytes)
+{
+    unsigned char tmp, k[256], *s;
+    unsigned i, j;
+
+    s = ctx->s;
+    assert(keybytes <= 256);
+    ctx->i = ctx->j = 0;
+    for (i = 0; i < 256; i++) {
+       s[i] = i;
+       k[i] = key[i % keybytes];
+    }
+    j = 0;
+    for (i = 0; i < 256; i++) {
+       j = (j + s[i] + k[i]) & 0xff;
+       tmp = s[i]; s[i] = s[j]; s[j] = tmp;
+    }
+}
+
+/* -- Interface with PuTTY -- */
+
+/*
+ * We don't implement Arcfour in SSH-1 because it's utterly insecure in
+ * several ways.  See CERT Vulnerability Notes VU#25309, VU#665372,
+ * and VU#565052.
+ * 
+ * We don't implement the "arcfour" algorithm in SSH-2 because it doesn't
+ * stir the cipher state before emitting keystream, and hence is likely
+ * to leak data about the key.
+ */
+
+static void *arcfour_make_context(void)
+{
+    return snew(ArcfourContext);
+}
+
+static void arcfour_free_context(void *handle)
+{
+    sfree(handle);
+}
+
+static void arcfour_stir(ArcfourContext *ctx)
+{
+    unsigned char *junk = snewn(1536, unsigned char);
+    memset(junk, 0, 1536);
+    arcfour_block(ctx, junk, 1536);
+    memset(junk, 0, 1536);
+    sfree(junk);
+}
+
+static void arcfour128_key(void *handle, unsigned char *key)
+{
+    ArcfourContext *ctx = (ArcfourContext *)handle;
+    arcfour_setkey(ctx, key, 16);
+    arcfour_stir(ctx);
+}
+
+static void arcfour256_key(void *handle, unsigned char *key)
+{
+    ArcfourContext *ctx = (ArcfourContext *)handle;
+    arcfour_setkey(ctx, key, 32);
+    arcfour_stir(ctx);
+}
+
+static void arcfour_iv(void *handle, unsigned char *key)
+{
+
+}
+
+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"
+};
+
+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"
+};
+
+/*
+ * arcfour256-draft-00@putty.projects.tartarus.org is as-yet untested
+ * against any other implementation, and hence is commented out.
+ */
+static const struct ssh2_cipher *const arcfour_list[] = {
+/*  &ssh_arcfour256_ssh2, */
+    &ssh_arcfour128_ssh2,
+};
+
+const struct ssh2_ciphers ssh2_arcfour = {
+    sizeof(arcfour_list) / sizeof(*arcfour_list),
+    arcfour_list
+};