[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.15 and 1.16

version 1.15, 1999/11/22 21:02:38 version 1.16, 1999/11/23 22:25:53
Line 33 
Line 33 
  */   */
 void  void
 SSH_3CBC_ENCRYPT(des_key_schedule ks1,  SSH_3CBC_ENCRYPT(des_key_schedule ks1,
                  des_key_schedule ks2, des_cblock *iv2,                   des_key_schedule ks2, des_cblock * iv2,
                  des_key_schedule ks3, des_cblock *iv3,                   des_key_schedule ks3, des_cblock * iv3,
                  void *dest, void *src,                   void *dest, void *src,
                  unsigned int len)                   unsigned int len)
 {  {
   des_cblock iv1;          des_cblock iv1;
   
   memcpy(&iv1, iv2, 8);          memcpy(&iv1, iv2, 8);
   
   des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);          des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT);
   memcpy(&iv1, dest + len - 8, 8);          memcpy(&iv1, dest + len - 8, 8);
   
   des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);          des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT);
   memcpy(iv2, &iv1, 8);         /* Note how iv1 == iv2 on entry and exit. */          memcpy(iv2, &iv1, 8);   /* Note how iv1 == iv2 on entry and exit. */
   
   des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);          des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT);
   memcpy(iv3, dest + len - 8, 8);          memcpy(iv3, dest + len - 8, 8);
 }  }
   
 void  void
 SSH_3CBC_DECRYPT(des_key_schedule ks1,  SSH_3CBC_DECRYPT(des_key_schedule ks1,
                  des_key_schedule ks2, des_cblock *iv2,                   des_key_schedule ks2, des_cblock * iv2,
                  des_key_schedule ks3, des_cblock *iv3,                   des_key_schedule ks3, des_cblock * iv3,
                  void *dest, void *src,                   void *dest, void *src,
                  unsigned int len)                   unsigned int len)
 {  {
   des_cblock iv1;          des_cblock iv1;
   
   memcpy(&iv1, iv2, 8);          memcpy(&iv1, iv2, 8);
   
   des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);          des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT);
   memcpy(iv3, src + len - 8, 8);          memcpy(iv3, src + len - 8, 8);
   
   des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);          des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT);
   memcpy(iv2, dest + len - 8, 8);          memcpy(iv2, dest + len - 8, 8);
   
   des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);          des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT);
   /* memcpy(&iv1, iv2, 8); */   /* Note how iv1 == iv2 on entry and exit. */          /* memcpy(&iv1, iv2, 8); */
           /* Note how iv1 == iv2 on entry and exit. */
 }  }
   
 /*  /*
  * SSH uses a variation on Blowfish, all bytes must be swapped before   * SSH 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  static void
 void  
 swap_bytes(const unsigned char *src, unsigned char *dst_, int n)  swap_bytes(const unsigned char *src, unsigned char *dst_, int n)
 {  {
   u_int32_t *dst = (u_int32_t *)dst_;   /* dst must be properly aligned. */          /* dst must be properly aligned. */
   union {          u_int32_t *dst = (u_int32_t *) dst_;
     u_int32_t i;          union {
     char c[4];                  u_int32_t i;
   } t;                  char c[4];
           } t;
   
   /* Process 8 bytes every lap. */          /* Process 8 bytes every lap. */
   for (n = n / 8; n > 0; n--)          for (n = n / 8; n > 0; n--) {
     {                  t.c[3] = *src++;
       t.c[3] = *src++;                  t.c[2] = *src++;
       t.c[2] = *src++;                  t.c[1] = *src++;
       t.c[1] = *src++;                  t.c[0] = *src++;
       t.c[0] = *src++;                  *dst++ = t.i;
       *dst++ = t.i;  
                   t.c[3] = *src++;
       t.c[3] = *src++;                  t.c[2] = *src++;
       t.c[2] = *src++;                  t.c[1] = *src++;
       t.c[1] = *src++;                  t.c[0] = *src++;
       t.c[0] = *src++;                  *dst++ = t.i;
       *dst++ = t.i;          }
     }  
 }  }
   
 void (*cipher_attack_detected)(const char *fmt, ...) = fatal;  void (*cipher_attack_detected) (const char *fmt,...) = fatal;
   
 static inline  static inline void
 void  
 detect_cbc_attack(const unsigned char *src,  detect_cbc_attack(const unsigned char *src,
                   unsigned int len)                    unsigned int len)
 {  {
   return;          return;
   
   log("CRC-32 CBC insertion attack detected");          log("CRC-32 CBC insertion attack detected");
   cipher_attack_detected("CRC-32 CBC insertion attack detected");          cipher_attack_detected("CRC-32 CBC insertion attack detected");
 }  }
   
 /* Names of all encryption algorithms.  These must match the numbers defined  /* Names of all encryption algorithms.  These must match the numbers defined
    int cipher.h. */     int cipher.h. */
 static char *cipher_names[] =  static char *cipher_names[] =
 {  {
   "none",          "none",
   "idea",          "idea",
   "des",          "des",
   "3des",          "3des",
   "tss",          "tss",
   "rc4",          "rc4",
   "blowfish"          "blowfish"
 };  };
   
 /* Returns a bit mask indicating which ciphers are supported by this  /* Returns a bit mask indicating which ciphers are supported by this
    implementation.  The bit mask has the corresponding bit set of each     implementation.  The bit mask has the corresponding bit set of each
    supported cipher. */     supported cipher. */
   
 unsigned int cipher_mask()  unsigned int
   cipher_mask()
 {  {
   unsigned int mask = 0;          unsigned int mask = 0;
   mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */          mask |= 1 << SSH_CIPHER_3DES;           /* Mandatory */
   mask |= 1 << SSH_CIPHER_BLOWFISH;          mask |= 1 << SSH_CIPHER_BLOWFISH;
   return mask;          return mask;
 }  }
   
 /* Returns the name of the cipher. */  /* Returns the name of the cipher. */
   
 const  const char *
 char *cipher_name(int cipher)  cipher_name(int cipher)
 {  {
   if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||          if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
         cipher_names[cipher] == NULL)              cipher_names[cipher] == NULL)
     fatal("cipher_name: bad cipher number: %d", cipher);                  fatal("cipher_name: bad cipher number: %d", cipher);
   return cipher_names[cipher];          return cipher_names[cipher];
 }  }
   
 /* Parses the name of the cipher.  Returns the number of the corresponding  /* Parses the name of the cipher.  Returns the number of the corresponding
Line 159 
Line 159 
 int  int
 cipher_number(const char *name)  cipher_number(const char *name)
 {  {
   int i;          int i;
   for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)          for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++)
     if (strcmp(cipher_names[i], name) == 0 &&                  if (strcmp(cipher_names[i], name) == 0 &&
         (cipher_mask() & (1 << i)))                      (cipher_mask() & (1 << i)))
       return i;                          return i;
   return -1;          return -1;
 }  }
   
 /* Selects the cipher, and keys if by computing the MD5 checksum of the  /* Selects the cipher, and keys if by computing the MD5 checksum of the
    passphrase and using the resulting 16 bytes as the key. */     passphrase and using the resulting 16 bytes as the key. */
   
 void cipher_set_key_string(CipherContext *context, int cipher,  void
                            const char *passphrase, int for_encryption)  cipher_set_key_string(CipherContext *context, int cipher,
                         const char *passphrase, int for_encryption)
 {  {
   MD5_CTX md;          MD5_CTX md;
   unsigned char digest[16];          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, for_encryption);          MD5_Init(&md);
           MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
   memset(digest, 0, sizeof(digest));          MD5_Final(digest, &md);
   memset(&md, 0, sizeof(md));  
           cipher_set_key(context, cipher, digest, 16, for_encryption);
   
           memset(digest, 0, sizeof(digest));
           memset(&md, 0, sizeof(md));
 }  }
   
 /* Selects the cipher to use and sets the key. */  /* Selects the cipher to use and sets the key. */
   
 void cipher_set_key(CipherContext *context, int cipher,  void
                     const unsigned char *key, int keylen, int for_encryption)  cipher_set_key(CipherContext *context, int cipher,
                  const unsigned char *key, int keylen, int for_encryption)
 {  {
   unsigned char padded[32];          unsigned char padded[32];
   
   /* Set cipher type. */          /* Set cipher type. */
   context->type = cipher;          context->type = cipher;
   
   /* Get 32 bytes of key data.  Pad if necessary.  (So that code below does          /* Get 32 bytes of key data.  Pad if necessary.  (So that code
      not need to worry about key size). */             below does not need to worry about key size). */
   memset(padded, 0, sizeof(padded));          memset(padded, 0, sizeof(padded));
   memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));          memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded));
   
   /* Initialize the initialization vector. */          /* Initialize the initialization vector. */
   switch (cipher)          switch (cipher) {
     {          case SSH_CIPHER_NONE:
     case SSH_CIPHER_NONE:                  /* Has to stay for authfile saving of private key with
       /* Has to stay for authfile saving of private key with no passphrase */                     no passphrase */
       break;                  break;
   
     case SSH_CIPHER_3DES:          case SSH_CIPHER_3DES:
       /* Note: the least significant bit of each byte of key is parity,                  /* Note: the least significant bit of each byte of key is
          and must be ignored by the implementation.  16 bytes of key are                     parity, and must be ignored by the implementation.  16
          used (first and last keys are the same). */                     bytes of key are used (first and last keys are the
       if (keylen < 16)                     same). */
         error("Key length %d is insufficient for 3DES.", keylen);                  if (keylen < 16)
       des_set_key((void*)padded, context->u.des3.key1);                          error("Key length %d is insufficient for 3DES.", keylen);
       des_set_key((void*)(padded + 8), context->u.des3.key2);                  des_set_key((void *) padded, context->u.des3.key1);
       if (keylen <= 16)                  des_set_key((void *) (padded + 8), context->u.des3.key2);
         des_set_key((void*)padded, context->u.des3.key3);                  if (keylen <= 16)
       else                          des_set_key((void *) padded, context->u.des3.key3);
         des_set_key((void*)(padded + 16), context->u.des3.key3);                  else
       memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));                          des_set_key((void *) (padded + 16), context->u.des3.key3);
       memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));                  memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2));
       break;                  memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3));
                   break;
   
     case SSH_CIPHER_BLOWFISH:          case SSH_CIPHER_BLOWFISH:
       BF_set_key(&context->u.bf.key, keylen, padded);                  BF_set_key(&context->u.bf.key, keylen, padded);
       memset(context->u.bf.iv, 0, 8);                  memset(context->u.bf.iv, 0, 8);
       break;                  break;
   
     default:          default:
       fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));                  fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
     }          }
   memset(padded, 0, sizeof(padded));          memset(padded, 0, sizeof(padded));
 }  }
   
 /* Encrypts data using the cipher. */  /* Encrypts data using the cipher. */
   
 void cipher_encrypt(CipherContext *context, unsigned char *dest,  void
                     const unsigned char *src, unsigned int len)  cipher_encrypt(CipherContext *context, unsigned char *dest,
                  const unsigned char *src, unsigned int len)
 {  {
   if ((len & 7) != 0)          if ((len & 7) != 0)
     fatal("cipher_encrypt: bad plaintext length %d", len);                  fatal("cipher_encrypt: bad plaintext length %d", len);
   
   switch (context->type)          switch (context->type) {
     {          case SSH_CIPHER_NONE:
     case SSH_CIPHER_NONE:                  memcpy(dest, src, len);
       memcpy(dest, src, len);                  break;
       break;  
   
     case SSH_CIPHER_3DES:          case SSH_CIPHER_3DES:
       SSH_3CBC_ENCRYPT(context->u.des3.key1,                  SSH_3CBC_ENCRYPT(context->u.des3.key1,
                        context->u.des3.key2, &context->u.des3.iv2,                                   context->u.des3.key2, &context->u.des3.iv2,
                        context->u.des3.key3, &context->u.des3.iv3,                                   context->u.des3.key3, &context->u.des3.iv3,
                        dest, (void*)src, len);                                   dest, (void *) src, len);
       break;                  break;
   
     case SSH_CIPHER_BLOWFISH:          case SSH_CIPHER_BLOWFISH:
       swap_bytes(src, dest, len);                  swap_bytes(src, dest, len);
       BF_cbc_encrypt(dest, dest, len,                  BF_cbc_encrypt(dest, dest, len,
                      &context->u.bf.key, context->u.bf.iv, BF_ENCRYPT);                                 &context->u.bf.key, context->u.bf.iv,
       swap_bytes(dest, dest, len);                                 BF_ENCRYPT);
       break;                  swap_bytes(dest, dest, len);
                   break;
   
     default:          default:
       fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));                  fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
     }          }
 }  }
   
 /* Decrypts data using the cipher. */  /* Decrypts data using the cipher. */
   
 void cipher_decrypt(CipherContext *context, unsigned char *dest,  void
                     const unsigned char *src, unsigned int len)  cipher_decrypt(CipherContext *context, unsigned char *dest,
                  const unsigned char *src, unsigned int len)
 {  {
   if ((len & 7) != 0)          if ((len & 7) != 0)
     fatal("cipher_decrypt: bad ciphertext length %d", len);                  fatal("cipher_decrypt: bad ciphertext length %d", len);
   
   switch (context->type)          switch (context->type) {
     {          case SSH_CIPHER_NONE:
     case SSH_CIPHER_NONE:                  memcpy(dest, src, len);
       memcpy(dest, src, len);                  break;
       break;  
   
     case SSH_CIPHER_3DES:          case SSH_CIPHER_3DES:
       /* CRC-32 attack? */                  /* CRC-32 attack? */
       SSH_3CBC_DECRYPT(context->u.des3.key1,                  SSH_3CBC_DECRYPT(context->u.des3.key1,
                        context->u.des3.key2, &context->u.des3.iv2,                                   context->u.des3.key2, &context->u.des3.iv2,
                        context->u.des3.key3, &context->u.des3.iv3,                                   context->u.des3.key3, &context->u.des3.iv3,
                        dest, (void*)src, len);                                   dest, (void *) src, len);
       break;                  break;
   
     case SSH_CIPHER_BLOWFISH:          case SSH_CIPHER_BLOWFISH:
       detect_cbc_attack(src, len);                  detect_cbc_attack(src, len);
       swap_bytes(src, dest, len);                  swap_bytes(src, dest, len);
       BF_cbc_encrypt((void*)dest, dest, len,                  BF_cbc_encrypt((void *) dest, dest, len,
                      &context->u.bf.key, context->u.bf.iv, BF_DECRYPT);                                 &context->u.bf.key, context->u.bf.iv,
       swap_bytes(dest, dest, len);                                 BF_DECRYPT);
       break;                  swap_bytes(dest, dest, len);
                   break;
   
     default:          default:
       fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));                  fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
     }          }
 }  }

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.16