[BACK]Return to cipher.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/cipher.c between version 1.26.2.5 and 1.27

version 1.26.2.5, 2001/03/21 18:52:40 version 1.27, 2000/05/22 18:42:00
Line 1 
Line 1 
 /*  /*
    *
    * cipher.c
    *
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Author: Tatu Ylonen <ylo@cs.hut.fi>
    *
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved   *                    All rights reserved
  *   *
  * As far as I am concerned, the code I have written for this software   * Created: Wed Apr 19 17:41:39 1995 ylo
  * can be used freely for any purpose.  Any derived versions of this  
  * software must be clearly marked as such, and if the derived work is  
  * incompatible with the protocol description in the RFC file, it must be  
  * called by a name other than "ssh" or "Secure Shell".  
  *   *
  *  
  * Copyright (c) 1999 Niels Provos.  All rights reserved.  
  * Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.  
  *  
  * Redistribution and use in source and binary forms, with or without  
  * modification, are permitted provided that the following conditions  
  * are met:  
  * 1. Redistributions of source code must retain the above copyright  
  *    notice, this list of conditions and the following disclaimer.  
  * 2. Redistributions in binary form must reproduce the above copyright  
  *    notice, this list of conditions and the following disclaimer in the  
  *    documentation and/or other materials provided with the distribution.  
  *  
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR  
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES  
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,  
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  */   */
   
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$Id$");
   
 #include "xmalloc.h"  #include "ssh.h"
 #include "log.h"  
 #include "cipher.h"  #include "cipher.h"
   #include "xmalloc.h"
   
 #include <openssl/md5.h>  #include <openssl/md5.h>
   
   
 /* no encryption */  
 void  
 none_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {  
 }  
 void  
 none_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  
 {  
 }  
 void  
 none_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         memcpy(dest, src, len);  
 }  
   
 /* DES */  
 void  
 des_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {  
         static int dowarn = 1;  
         if (dowarn) {  
                 error("Warning: use of DES is strongly discouraged "  
                     "due to cryptographic weaknesses");  
                 dowarn = 0;  
         }  
         des_set_key((void *)key, cc->u.des.key);  
 }  
 void  
 des_ssh1_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  
 {  
         memset(cc->u.des.iv, 0, sizeof(cc->u.des.iv));  
 }  
 void  
 des_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,  
             DES_ENCRYPT);  
 }  
 void  
 des_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         des_ncbc_encrypt(src, dest, len, cc->u.des.key, &cc->u.des.iv,  
             DES_DECRYPT);  
 }  
   
 /* 3DES */  
 void  
 des3_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {  
         des_set_key((void *) key, cc->u.des3.key1);  
         des_set_key((void *) (key+8), cc->u.des3.key2);  
         des_set_key((void *) (key+16), cc->u.des3.key3);  
 }  
 void  
 des3_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  
 {  
         memset(cc->u.des3.iv2, 0, sizeof(cc->u.des3.iv2));  
         memset(cc->u.des3.iv3, 0, sizeof(cc->u.des3.iv3));  
         if (iv == NULL)  
                 return;  
         memcpy(cc->u.des3.iv3, (char *)iv, 8);  
 }  
 void  
 des3_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         des_ede3_cbc_encrypt(src, dest, len,  
             cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,  
             &cc->u.des3.iv3, DES_ENCRYPT);  
 }  
 void  
 des3_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         des_ede3_cbc_encrypt(src, dest, len,  
             cc->u.des3.key1, cc->u.des3.key2, cc->u.des3.key3,  
             &cc->u.des3.iv3, DES_DECRYPT);  
 }  
   
 /*  /*
  * This is used by SSH1:   * This is used by SSH1:
  *   *
Line 136 
Line 35 
  * choosing the X block.   * choosing the X block.
  */   */
 void  void
 des3_ssh1_setkey(CipherContext *cc, const u_char *key, u_int keylen)  SSH_3CBC_ENCRYPT(des_key_schedule ks1,
                    des_key_schedule ks2, des_cblock * iv2,
                    des_key_schedule ks3, des_cblock * iv3,
                    unsigned char *dest, unsigned char *src,
                    unsigned int len)
 {  {
         des_set_key((void *) key, cc->u.des3.key1);  
         des_set_key((void *) (key+8), cc->u.des3.key2);  
         if (keylen <= 16)  
                 des_set_key((void *) key, cc->u.des3.key3);  
         else  
                 des_set_key((void *) (key+16), cc->u.des3.key3);  
 }  
 void  
 des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,  
     u_int len)  
 {  
         des_cblock iv1;          des_cblock iv1;
         des_cblock *iv2 = &cc->u.des3.iv2;  
         des_cblock *iv3 = &cc->u.des3.iv3;  
   
         memcpy(&iv1, iv2, 8);          memcpy(&iv1, iv2, 8);
   
         des_ncbc_encrypt(src,  dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);          des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
         des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);          memcpy(&iv1, dest + len - 8, 8);
         des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);  
           des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
           memcpy(iv2, &iv1, 8);   /* Note how iv1 == iv2 on entry and exit. */
   
           des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
           memcpy(iv3, dest + len - 8, 8);
 }  }
   
 void  void
 des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,  SSH_3CBC_DECRYPT(des_key_schedule ks1,
     u_int len)                   des_key_schedule ks2, des_cblock * iv2,
                    des_key_schedule ks3, des_cblock * iv3,
                    unsigned char *dest, unsigned char *src,
                    unsigned int len)
 {  {
         des_cblock iv1;          des_cblock iv1;
         des_cblock *iv2 = &cc->u.des3.iv2;  
         des_cblock *iv3 = &cc->u.des3.iv3;  
   
         memcpy(&iv1, iv2, 8);          memcpy(&iv1, iv2, 8);
   
         des_ncbc_encrypt(src,  dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);          des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
         des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);          memcpy(iv3, src + len - 8, 8);
         des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);  
 }  
   
 /* Blowfish */          des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
 void          memcpy(iv2, dest + len - 8, 8);
 blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {          des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
         BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);          /* memcpy(&iv1, iv2, 8); */
           /* Note how iv1 == iv2 on entry and exit. */
 }  }
 void  
 blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  
 {  
         if (iv == NULL)  
                 memset(cc->u.bf.iv, 0, 8);  
         else  
                 memcpy(cc->u.bf.iv, (char *)iv, 8);  
 }  
 void  
 blowfish_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,  
      u_int len)  
 {  
         BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,  
             BF_ENCRYPT);  
 }  
 void  
 blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,  
      u_int len)  
 {  
         BF_cbc_encrypt((void *)src, dest, len, &cc->u.bf.key, cc->u.bf.iv,  
             BF_DECRYPT);  
 }  
   
 /*  /*
  * SSH1 uses a variation on Blowfish, all bytes must be swapped before   * SSH1 uses a variation on Blowfish, all bytes must be swapped before
  * and after encryption/decryption. Thus the swap_bytes stuff (yuk).   * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
  */   */
 static void  static void
 swap_bytes(const u_char *src, u_char *dst, int n)  swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
 {  {
         char c[4];          /* dst must be properly aligned. */
           u_int32_t *dst = (u_int32_t *) dst_;
           union {
                   u_int32_t i;
                   char c[4];
           } t;
   
         /* Process 4 bytes every lap. */          /* Process 8 bytes every lap. */
         for (n = n / 4; n > 0; n--) {          for (n = n / 8; n > 0; n--) {
                 c[3] = *src++;                  t.c[3] = *src++;
                 c[2] = *src++;                  t.c[2] = *src++;
                 c[1] = *src++;                  t.c[1] = *src++;
                 c[0] = *src++;                  t.c[0] = *src++;
                   *dst++ = t.i;
   
                 *dst++ = c[0];                  t.c[3] = *src++;
                 *dst++ = c[1];                  t.c[2] = *src++;
                 *dst++ = c[2];                  t.c[1] = *src++;
                 *dst++ = c[3];                  t.c[0] = *src++;
                   *dst++ = t.i;
         }          }
 }  }
   
 void  /*
 blowfish_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,   * Names of all encryption algorithms.
     u_int len)   * These must match the numbers defined in cipher.h.
    */
   static char *cipher_names[] =
 {  {
         swap_bytes(src, dest, len);          "none",
         BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,          "idea",
             BF_ENCRYPT);          "des",
         swap_bytes(dest, dest, len);          "3des",
 }          "tss",
 void          "rc4",
 blowfish_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,          "blowfish",
     u_int len)          "reserved",
 {          "blowfish-cbc",
         swap_bytes(src, dest, len);          "3des-cbc",
         BF_cbc_encrypt((void *)dest, dest, len, &cc->u.bf.key, cc->u.bf.iv,          "arcfour",
             BF_DECRYPT);          "cast128-cbc"
         swap_bytes(dest, dest, len);  };
 }  
   
 /* alleged rc4 */  /*
 void   * Returns a bit mask indicating which ciphers are supported by this
 arcfour_setkey(CipherContext *cc, const u_char *key, u_int keylen)   * implementation.  The bit mask has the corresponding bit set of each
 {   * supported cipher.
         RC4_set_key(&cc->u.rc4, keylen, (u_char *)key);   */
 }  
 void  
 arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         RC4(&cc->u.rc4, len, (u_char *)src, dest);  
 }  
   
 /* CAST */  unsigned int
 void  cipher_mask1()
 cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {  {
         CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);          unsigned int mask = 0;
           mask |= 1 << SSH_CIPHER_3DES;           /* Mandatory */
           mask |= 1 << SSH_CIPHER_BLOWFISH;
           return mask;
 }  }
 void  unsigned int
 cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  cipher_mask2()
 {  {
         if (iv == NULL)          unsigned int mask = 0;
                 fatal("no IV for %s.", cc->cipher->name);          mask |= 1 << SSH_CIPHER_BLOWFISH_CBC;
         memcpy(cc->u.cast.iv, (char *)iv, 8);          mask |= 1 << SSH_CIPHER_3DES_CBC;
           mask |= 1 << SSH_CIPHER_ARCFOUR;
           mask |= 1 << SSH_CIPHER_CAST128_CBC;
           return mask;
 }  }
 void  unsigned int
 cast_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  cipher_mask()
 {  {
         CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,          return cipher_mask1() | cipher_mask2();
             CAST_ENCRYPT);  
 }  }
 void  
 cast_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  
 {  
         CAST_cbc_encrypt(src, dest, len, &cc->u.cast.key, cc->u.cast.iv,  
             CAST_DECRYPT);  
 }  
   
 /* RIJNDAEL */  /* Returns the name of the cipher. */
   
 #define RIJNDAEL_BLOCKSIZE 16  const char *
 void  cipher_name(int cipher)
 rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)  
 {  {
         rijndael_set_key(&cc->u.rijndael.enc, (u4byte *)key, 8*keylen, 1);          if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
         rijndael_set_key(&cc->u.rijndael.dec, (u4byte *)key, 8*keylen, 0);              cipher_names[cipher] == NULL)
                   fatal("cipher_name: bad cipher name: %d", cipher);
           return cipher_names[cipher];
 }  }
 void  
 rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)  
 {  
         if (iv == NULL)  
                 fatal("no IV for %s.", cc->cipher->name);  
         memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);  
 }  
 void  
 rijndael_cbc_encrypt(CipherContext *cc, u_char *dest, const u_char *src,  
     u_int len)  
 {  
         rijndael_ctx *ctx = &cc->u.rijndael.enc;  
         u4byte *iv = cc->u.rijndael.iv;  
         u4byte in[4];  
         u4byte *cprev, *cnow, *plain;  
         int i, blocks = len / RIJNDAEL_BLOCKSIZE;  
         if (len == 0)  
                 return;  
         if (len % RIJNDAEL_BLOCKSIZE)  
                 fatal("rijndael_cbc_encrypt: bad len %d", len);  
         cnow  = (u4byte*) dest;  
         plain = (u4byte*) src;  
         cprev = iv;  
         for(i = 0; i < blocks; i++, plain+=4, cnow+=4) {  
                 in[0] = plain[0] ^ cprev[0];  
                 in[1] = plain[1] ^ cprev[1];  
                 in[2] = plain[2] ^ cprev[2];  
                 in[3] = plain[3] ^ cprev[3];  
                 rijndael_encrypt(ctx, in, cnow);  
                 cprev = cnow;  
         }  
         memcpy(iv, cprev, RIJNDAEL_BLOCKSIZE);  
 }  
   
 void  /* Returns 1 if the name of the ciphers are valid. */
 rijndael_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,  
     u_int len)  
 {  
         rijndael_ctx *ctx = &cc->u.rijndael.dec;  
         u4byte *iv = cc->u.rijndael.iv;  
         u4byte ivsaved[4];  
         u4byte *cnow =  (u4byte*) (src+len-RIJNDAEL_BLOCKSIZE);  
         u4byte *plain = (u4byte*) (dest+len-RIJNDAEL_BLOCKSIZE);  
         u4byte *ivp;  
         int i, blocks = len / RIJNDAEL_BLOCKSIZE;  
         if (len == 0)  
                 return;  
         if (len % RIJNDAEL_BLOCKSIZE)  
                 fatal("rijndael_cbc_decrypt: bad len %d", len);  
         memcpy(ivsaved, cnow, RIJNDAEL_BLOCKSIZE);  
         for(i = blocks; i > 0; i--, cnow-=4, plain-=4) {  
                 rijndael_decrypt(ctx, cnow, plain);  
                 ivp =  (i == 1) ? iv : cnow-4;  
                 plain[0] ^= ivp[0];  
                 plain[1] ^= ivp[1];  
                 plain[2] ^= ivp[2];  
                 plain[3] ^= ivp[3];  
         }  
         memcpy(iv, ivsaved, RIJNDAEL_BLOCKSIZE);  
 }  
   
 Cipher ciphers[] = {  
         { "none",  
                 SSH_CIPHER_NONE, 8, 0,  
                 none_setkey, none_setiv,  
                 none_crypt, none_crypt },  
         { "des",  
                 SSH_CIPHER_DES, 8, 8,  
                 des_ssh1_setkey, des_ssh1_setiv,  
                 des_ssh1_encrypt, des_ssh1_decrypt },  
         { "3des",  
                 SSH_CIPHER_3DES, 8, 16,  
                 des3_ssh1_setkey, des3_setiv,  
                 des3_ssh1_encrypt, des3_ssh1_decrypt },  
         { "blowfish",  
                 SSH_CIPHER_BLOWFISH, 8, 16,  
                 blowfish_setkey, blowfish_setiv,  
                 blowfish_ssh1_encrypt, blowfish_ssh1_decrypt },  
   
         { "3des-cbc",  
                 SSH_CIPHER_SSH2, 8, 24,  
                 des3_setkey, des3_setiv,  
                 des3_cbc_encrypt, des3_cbc_decrypt },  
         { "blowfish-cbc",  
                 SSH_CIPHER_SSH2, 8, 16,  
                 blowfish_setkey, blowfish_setiv,  
                 blowfish_cbc_encrypt, blowfish_cbc_decrypt },  
         { "cast128-cbc",  
                 SSH_CIPHER_SSH2, 8, 16,  
                 cast_setkey, cast_setiv,  
                 cast_cbc_encrypt, cast_cbc_decrypt },  
         { "arcfour",  
                 SSH_CIPHER_SSH2, 8, 16,  
                 arcfour_setkey, none_setiv,  
                 arcfour_crypt, arcfour_crypt },  
         { "aes128-cbc",  
                 SSH_CIPHER_SSH2, 16, 16,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "aes192-cbc",  
                 SSH_CIPHER_SSH2, 16, 24,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "aes256-cbc",  
                 SSH_CIPHER_SSH2, 16, 32,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "rijndael128-cbc",  
                 SSH_CIPHER_SSH2, 16, 16,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "rijndael192-cbc",  
                 SSH_CIPHER_SSH2, 16, 24,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "rijndael256-cbc",  
                 SSH_CIPHER_SSH2, 16, 32,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { "rijndael-cbc@lysator.liu.se",  
                 SSH_CIPHER_SSH2, 16, 32,  
                 rijndael_setkey, rijndael_setiv,  
                 rijndael_cbc_encrypt, rijndael_cbc_decrypt },  
         { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }  
 };  
   
 /*--*/  
   
 u_int  
 cipher_mask_ssh1(int client)  
 {  
         u_int mask = 0;  
         mask |= 1 << SSH_CIPHER_3DES;           /* Mandatory */  
         mask |= 1 << SSH_CIPHER_BLOWFISH;  
         if (client) {  
                 mask |= 1 << SSH_CIPHER_DES;  
         }  
         return mask;  
 }  
   
 Cipher *  
 cipher_by_name(const char *name)  
 {  
         Cipher *c;  
         for (c = ciphers; c->name != NULL; c++)  
                 if (strcasecmp(c->name, name) == 0)  
                         return c;  
         return NULL;  
 }  
   
 Cipher *  
 cipher_by_number(int id)  
 {  
         Cipher *c;  
         for (c = ciphers; c->name != NULL; c++)  
                 if (c->number == id)  
                         return c;  
         return NULL;  
 }  
   
 #define CIPHER_SEP      ","  #define CIPHER_SEP      ","
 int  int
 ciphers_valid(const char *names)  ciphers_valid(const char *names)
 {  {
         Cipher *c;          char *ciphers;
         char *ciphers, *cp;  
         char *p;          char *p;
           int i;
   
         if (names == NULL || strcmp(names, "") == 0)          if (names == NULL || strcmp(names, "") == 0)
                 return 0;                  return 0;
         ciphers = cp = xstrdup(names);          ciphers = xstrdup(names);
         for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';          for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) {
              (p = strsep(&cp, CIPHER_SEP))) {                  i = cipher_number(p);
                 c = cipher_by_name(p);                  if (i == -1 || !(cipher_mask2() & (1 << i))) {
                 if (c == NULL || c->number != SSH_CIPHER_SSH2) {  
                         debug("bad cipher %s [%s]", p, names);  
                         xfree(ciphers);                          xfree(ciphers);
                         return 0;                          return 0;
                 } else {  
                         debug3("cipher ok: %s [%s]", p, names);  
                 }                  }
         }          }
         debug3("ciphers ok: [%s]", names);  
         xfree(ciphers);          xfree(ciphers);
         return 1;          return 1;
 }  }
Line 487 
Line 200 
 int  int
 cipher_number(const char *name)  cipher_number(const char *name)
 {  {
         Cipher *c;          int i;
         if (name == NULL)          if (name == NULL)
                 return -1;                  return -1;
         c = cipher_by_name(name);          for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
         return (c==NULL) ? -1 : c->number;                  if (strcmp(cipher_names[i], name) == 0 &&
                       (cipher_mask() & (1 << i)))
                           return i;
           return -1;
 }  }
   
 char *  /*
 cipher_name(int id)   * Selects the cipher, and keys if by computing the MD5 checksum of the
    * passphrase and using the resulting 16 bytes as the key.
    */
   
   void
   cipher_set_key_string(CipherContext *context, int cipher, const char *passphrase)
 {  {
         Cipher *c = cipher_by_number(id);          MD5_CTX md;
         return (c==NULL) ? "<unknown>" : c->name;          unsigned char digest[16];
   
           MD5_Init(&md);
           MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
           MD5_Final(digest, &md);
   
           cipher_set_key(context, cipher, digest, 16);
   
           memset(digest, 0, sizeof(digest));
           memset(&md, 0, sizeof(md));
 }  }
   
   /* Selects the cipher to use and sets the key. */
   
 void  void
 cipher_init(CipherContext *cc, Cipher *cipher,  cipher_set_key(CipherContext *context, int cipher, const unsigned char *key,
     const u_char *key, u_int keylen, const u_char *iv, u_int ivlen)      int keylen)
 {  {
         if (keylen < cipher->key_len)          unsigned char padded[32];
                 fatal("cipher_init: key length %d is insufficient for %s.",  
                     keylen, cipher->name);          /* Set cipher type. */
         if (iv != NULL && ivlen < cipher->block_size)          context->type = cipher;
                 fatal("cipher_init: iv length %d is insufficient for %s.",  
                     ivlen, cipher->name);          /* Get 32 bytes of key data.  Pad if necessary.  (So that code
         cc->cipher = cipher;             below does not need to worry about key size). */
         cipher->setkey(cc, key, keylen);          memset(padded, 0, sizeof(padded));
         cipher->setiv(cc, iv, ivlen);          memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
   
           /* Initialize the initialization vector. */
           switch (cipher) {
           case SSH_CIPHER_NONE:
                   /*
                    * Has to stay for authfile saving of private key with no
                    * passphrase
                    */
                   break;
   
           case SSH_CIPHER_3DES:
                   /*
                    * Note: the least significant bit of each byte of key is
                    * parity, and must be ignored by the implementation.  16
                    * bytes of key are used (first and last keys are the same).
                    */
                   if (keylen < 16)
                           error("Key length %d is insufficient for 3DES.", keylen);
                   des_set_key((void *) padded, context->u.des3.key1);
                   des_set_key((void *) (padded + 8), context->u.des3.key2);
                   if (keylen <= 16)
                           des_set_key((void *) padded, context->u.des3.key3);
                   else
                           des_set_key((void *) (padded + 16), context->u.des3.key3);
                   memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
                   memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
                   break;
   
           case SSH_CIPHER_BLOWFISH:
                   if (keylen < 16)
                           error("Key length %d is insufficient for blowfish.", keylen);
                   BF_set_key(&context->u.bf.key, keylen, padded);
                   memset(context->u.bf.iv, 0, 8);
                   break;
   
           case SSH_CIPHER_3DES_CBC:
           case SSH_CIPHER_BLOWFISH_CBC:
           case SSH_CIPHER_ARCFOUR:
           case SSH_CIPHER_CAST128_CBC:
                   fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher));
                   break;
   
           default:
                   fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
           }
           memset(padded, 0, sizeof(padded));
 }  }
   
 void  void
 cipher_encrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  cipher_set_key_iv(CipherContext * context, int cipher,
       const unsigned char *key, int keylen,
       const unsigned char *iv, int ivlen)
 {  {
         if (len % cc->cipher->block_size)          /* Set cipher type. */
                 fatal("cipher_encrypt: bad plaintext length %d", len);          context->type = cipher;
         cc->cipher->encrypt(cc, dest, src, len);  
           /* Initialize the initialization vector. */
           switch (cipher) {
           case SSH_CIPHER_NONE:
                   break;
   
           case SSH_CIPHER_3DES:
           case SSH_CIPHER_BLOWFISH:
                   fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher));
                   break;
   
           case SSH_CIPHER_3DES_CBC:
                   if (keylen < 24)
                           error("Key length %d is insufficient for 3des-cbc.", keylen);
                   des_set_key((void *) key, context->u.des3.key1);
                   des_set_key((void *) (key+8), context->u.des3.key2);
                   des_set_key((void *) (key+16), context->u.des3.key3);
                   if (ivlen < 8)
                           error("IV length %d is insufficient for 3des-cbc.", ivlen);
                   memcpy(context->u.des3.iv3, (char *)iv, 8);
                   break;
   
           case SSH_CIPHER_BLOWFISH_CBC:
                   if (keylen < 16)
                           error("Key length %d is insufficient for blowfish.", keylen);
                   if (ivlen < 8)
                           error("IV length %d is insufficient for blowfish.", ivlen);
                   BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key);
                   memcpy(context->u.bf.iv, (char *)iv, 8);
                   break;
   
           case SSH_CIPHER_ARCFOUR:
                   if (keylen < 16)
                           error("Key length %d is insufficient for arcfour.", keylen);
                   RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key);
                   break;
   
           case SSH_CIPHER_CAST128_CBC:
                   if (keylen < 16)
                           error("Key length %d is insufficient for cast128.", keylen);
                   if (ivlen < 8)
                           error("IV length %d is insufficient for cast128.", ivlen);
                   CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key);
                   memcpy(context->u.cast.iv, (char *)iv, 8);
                   break;
   
           default:
                   fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
           }
 }  }
   
   /* Encrypts data using the cipher. */
   
 void  void
 cipher_decrypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)  cipher_encrypt(CipherContext *context, unsigned char *dest,
                  const unsigned char *src, unsigned int len)
 {  {
         if (len % cc->cipher->block_size)          if ((len & 7) != 0)
                 fatal("cipher_decrypt: bad ciphertext length %d", len);                  fatal("cipher_encrypt: bad plaintext length %d", len);
         cc->cipher->decrypt(cc, dest, src, len);  
           switch (context->type) {
           case SSH_CIPHER_NONE:
                   memcpy(dest, src, len);
                   break;
   
           case SSH_CIPHER_3DES:
                   SSH_3CBC_ENCRYPT(context->u.des3.key1,
                                    context->u.des3.key2, &context->u.des3.iv2,
                                    context->u.des3.key3, &context->u.des3.iv3,
                                    dest, (unsigned char *) src, len);
                   break;
   
           case SSH_CIPHER_BLOWFISH:
                   swap_bytes(src, dest, len);
                   BF_cbc_encrypt(dest, dest, len,
                                  &context->u.bf.key, context->u.bf.iv,
                                  BF_ENCRYPT);
                   swap_bytes(dest, dest, len);
                   break;
   
           case SSH_CIPHER_BLOWFISH_CBC:
                   BF_cbc_encrypt((void *)src, dest, len,
                                  &context->u.bf.key, context->u.bf.iv,
                                  BF_ENCRYPT);
                   break;
   
           case SSH_CIPHER_3DES_CBC:
                   des_ede3_cbc_encrypt(src, dest, len,
                       context->u.des3.key1, context->u.des3.key2,
                       context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT);
                   break;
   
           case SSH_CIPHER_ARCFOUR:
                   RC4(&context->u.rc4, len, (unsigned char *)src, dest);
                   break;
   
           case SSH_CIPHER_CAST128_CBC:
                   CAST_cbc_encrypt(src, dest, len,
                       &context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT);
                   break;
   
           default:
                   fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
           }
 }  }
   
 /*  /* Decrypts data using the cipher. */
  * Selects the cipher, and keys if by computing the MD5 checksum of the  
  * passphrase and using the resulting 16 bytes as the key.  
  */  
   
 void  void
 cipher_set_key_string(CipherContext *cc, Cipher *cipher,  cipher_decrypt(CipherContext *context, unsigned char *dest,
     const char *passphrase)                 const unsigned char *src, unsigned int len)
 {  {
         MD5_CTX md;          if ((len & 7) != 0)
         u_char digest[16];                  fatal("cipher_decrypt: bad ciphertext length %d", len);
   
         MD5_Init(&md);          switch (context->type) {
         MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));          case SSH_CIPHER_NONE:
         MD5_Final(digest, &md);                  memcpy(dest, src, len);
                   break;
   
         cipher_init(cc, cipher, digest, 16, NULL, 0);          case SSH_CIPHER_3DES:
                   SSH_3CBC_DECRYPT(context->u.des3.key1,
                                    context->u.des3.key2, &context->u.des3.iv2,
                                    context->u.des3.key3, &context->u.des3.iv3,
                                    dest, (unsigned char *) src, len);
                   break;
   
         memset(digest, 0, sizeof(digest));          case SSH_CIPHER_BLOWFISH:
         memset(&md, 0, sizeof(md));                  swap_bytes(src, dest, len);
                   BF_cbc_encrypt((void *) dest, dest, len,
                                  &context->u.bf.key, context->u.bf.iv,
                                  BF_DECRYPT);
                   swap_bytes(dest, dest, len);
                   break;
   
           case SSH_CIPHER_BLOWFISH_CBC:
                   BF_cbc_encrypt((void *) src, dest, len,
                                  &context->u.bf.key, context->u.bf.iv,
                                  BF_DECRYPT);
                   break;
   
           case SSH_CIPHER_3DES_CBC:
                   des_ede3_cbc_encrypt(src, dest, len,
                       context->u.des3.key1, context->u.des3.key2,
                       context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT);
                   break;
   
           case SSH_CIPHER_ARCFOUR:
                   RC4(&context->u.rc4, len, (unsigned char *)src, dest);
                   break;
   
           case SSH_CIPHER_CAST128_CBC:
                   CAST_cbc_encrypt(src, dest, len,
                       &context->u.cast.key, context->u.cast.iv, CAST_DECRYPT);
                   break;
   
           default:
                   fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
           }
 }  }

Legend:
Removed from v.1.26.2.5  
changed lines
  Added in v.1.27