Hello,

I've updated the ciphertext stealing code a bit, and below is a new
patch against the latest CVS HEAD. Note that I have sent another TSU
notification for this patch in case this is considered different from
the previous patch (which was against 0.9.8d).

Please let me know if you have any suggestions or discover any problems. Thanks!

An-Cheng


Index: crypto/evp/evp.h
===================================================================
RCS file: /home/pach/prog/openssl/cvs/openssl/crypto/evp/evp.h,v
retrieving revision 1.170
diff -u -r1.170 evp.h
--- crypto/evp/evp.h    8 Feb 2007 19:07:43 -0000       1.170
+++ crypto/evp/evp.h    15 Mar 2007 06:13:20 -0000
@@ -328,6 +328,8 @@
 #define        EVP_CIPH_NO_PADDING             0x100
 /* cipher handles random key generation */
 #define        EVP_CIPH_RAND_KEY               0x200
+/* Use ciphertext stealing instead of padding */
+#define        EVP_CIPH_CIPHERTEXT_STEALING   0x400

  /* ctrl() values */

@@ -514,7 +516,10 @@
                const unsigned char *key, const unsigned char *iv);
  int   EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl, const unsigned char *in, int inl);
+int    EVP_EncryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                          int *outl, const unsigned char *in, int inl);
  int   EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+int    EVP_EncryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int 
*outl);
  int   EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);

  int   EVP_DecryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
@@ -523,7 +528,10 @@
                const unsigned char *key, const unsigned char *iv);
  int   EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
                int *outl, const unsigned char *in, int inl);
+int    EVP_DecryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                          int *outl, const unsigned char *in, int inl);
  int   EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
+int    EVP_DecryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *outm, int 
*outl);
  int   EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int 
*outl);

  int   EVP_CipherInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
@@ -582,6 +590,7 @@
 void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
  int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
 int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
+int EVP_CIPHER_CTX_set_cts(EVP_CIPHER_CTX *c, int cts);
  int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
  int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key);

@@ -1143,9 +1152,12 @@
 #define EVP_F_ECKEY_PKEY2PKCS8                          132
 #define EVP_F_EVP_CIPHERINIT_EX                                 123
 #define EVP_F_EVP_CIPHER_CTX_CTRL                       124
+#define EVP_F_EVP_CIPHER_CTX_SET_CTS                    161
 #define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH             122
+#define EVP_F_EVP_DECRYPTFINAL_CTS                      162
 #define EVP_F_EVP_DECRYPTFINAL_EX                       101
 #define EVP_F_EVP_DIGESTINIT_EX                                 128
+#define EVP_F_EVP_ENCRYPTFINAL_CTS                      163
 #define EVP_F_EVP_ENCRYPTFINAL_EX                       127
 #define EVP_F_EVP_MD_CTX_COPY_EX                        110
 #define EVP_F_EVP_OPENINIT                              102
@@ -1220,6 +1232,8 @@
 #define EVP_R_EXPECTING_A_DSA_KEY                       129
 #define EVP_R_EXPECTING_A_ECDSA_KEY                     141
 #define EVP_R_EXPECTING_A_EC_KEY                        142
+#define EVP_R_EXPECTING_PREVIOUS_CIPHERTEXT             158
+#define EVP_R_EXPECTING_PREVIOUS_PLAINTEXT              159
 #define EVP_R_INITIALIZATION_ERROR                      134
 #define EVP_R_INPUT_NOT_INITIALIZED                     111
 #define EVP_R_INVALID_DIGEST                            152
@@ -1249,6 +1263,7 @@
 #define EVP_R_UNSUPPORTED_KEYLENGTH                     123
 #define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION       124
 #define EVP_R_UNSUPPORTED_KEY_SIZE                      108
+#define EVP_R_UNSUPPORTED_MODE                          160
 #define EVP_R_UNSUPPORTED_PRF                           125
 #define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM                 118
 #define EVP_R_UNSUPPORTED_SALT_TYPE                     126
Index: crypto/evp/evp_enc.c
===================================================================
RCS file: /home/pach/prog/openssl/cvs/openssl/crypto/evp/evp_enc.c,v
retrieving revision 1.45
diff -u -r1.45 evp_enc.c
--- crypto/evp/evp_enc.c        21 Jan 2007 13:07:09 -0000      1.45
+++ crypto/evp/evp_enc.c        15 Mar 2007 06:05:13 -0000
@@ -274,12 +274,88 @@
        return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
        }

+int
+EVP_EncryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
+                      const unsigned char *in, int inl)
+{
+  int bl = ctx->cipher->block_size;
+  int leftover = 0;
+  OPENSSL_assert(bl <= (int)sizeof(ctx->buf));
+  *outl = 0;
+
+  if ((ctx->buf_len + inl) <= bl) {
+    /* new plaintext is no more than 1 block */
+    /* copy the in data into the buffer and return */
+    memcpy(&(ctx->buf[ctx->buf_len]), in, inl);
+    ctx->buf_len += inl;
+    *outl = 0;
+    return 1;
+  }
+
+  /* more than 1 block of new plaintext available */
+  /* encrypt the previous plaintext, if any */
+  if (ctx->final_used) {
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->final, bl))) {
+      return 0;
+    }
+    out += bl;
+    *outl += bl;
+    ctx->final_used = 0;
+  }
+
+  /* we already know ctx->buf_len + inl must be > bl */
+  memcpy(&(ctx->buf[ctx->buf_len]), in, (bl - ctx->buf_len));
+  in += (bl - ctx->buf_len);
+  inl -= (bl - ctx->buf_len);
+  ctx->buf_len = bl;
+
+  if (inl <= bl) {
+    memcpy(ctx->final, ctx->buf, bl);
+    ctx->final_used = 1;
+    memcpy(ctx->buf, in, inl);
+    ctx->buf_len = inl;
+    return 1;
+  } else {
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) {
+      return 0;
+    }
+    out += bl;
+    *outl += bl;
+    ctx->buf_len = 0;
+
+    leftover = inl & ctx->block_mask;
+    if (leftover) {
+      inl -= (bl + leftover);
+      memcpy(ctx->buf, &(in[(inl + bl)]), leftover);
+      ctx->buf_len = leftover;
+    } else {
+      inl -= (2 * bl);
+      memcpy(ctx->buf, &(in[(inl + bl)]), bl);
+      ctx->buf_len = bl;
+    }
+    memcpy(ctx->final, &(in[inl]), bl);
+    ctx->final_used = 1;
+    if (!(ctx->cipher->do_cipher(ctx, out, in, inl))) {
+      return 0;
+    }
+    out += inl;
+    *outl += inl;
+  }
+
+  return 1;
+}
+
  int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
             const unsigned char *in, int inl)
        {
        int i,j,bl;

        OPENSSL_assert(inl > 0);
+       if (ctx->flags & EVP_CIPH_CIPHERTEXT_STEALING)
+               {
+    return EVP_EncryptUpdate_cts(ctx, out, outl, in, inl);
+               }
+
        if(ctx->buf_len == 0 && (inl&(ctx->block_mask)) == 0)
                {
                if(ctx->cipher->do_cipher(ctx,out,in,inl))
@@ -339,11 +415,82 @@
        return ret;
        }

+int
+EVP_EncryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
+{
+  unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
+  int bl = ctx->cipher->block_size;
+  int leftover = 0;
+  *outl = 0;
+
+  if (!ctx->final_used) {
+    EVPerr(EVP_F_EVP_ENCRYPTFINAL_CTS, EVP_R_EXPECTING_PREVIOUS_CIPHERTEXT);
+    return 0;
+  }
+  if (ctx->buf_len == 0) {
+    EVPerr(EVP_F_EVP_ENCRYPTFINAL_CTS, EVP_R_EXPECTING_PREVIOUS_PLAINTEXT);
+    return 0;
+  }
+
+  /* handle leftover bytes */
+  leftover = ctx->buf_len;
+
+  switch (EVP_CIPHER_CTX_mode(ctx)) {
+  case EVP_CIPH_ECB_MODE: {
+    /* encrypt => C_{n} plus C' */
+    if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) {
+      return 0;
+    }
+
+    /* P_n plus C' */
+    memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover));
+    /* encrypt => C_{n-1} */
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) {
+      return 0;
+    }
+
+    memcpy((out + bl), tmp, leftover);
+    *outl += (bl + leftover);
+    return 1;
+  }
+  case EVP_CIPH_CBC_MODE: {
+    /* encrypt => C_{n} plus C' */
+    if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) {
+      return 0;
+    }
+
+    /* P_n plus 0s */
+    memset(&(ctx->buf[leftover]), 0, (bl - leftover));
+
+    /* note that in cbc encryption, plaintext will be xor'ed with the previous
+     * ciphertext, which is what we want.
+     */
+    /* encrypt => C_{n-1} */
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) {
+      return 0;
+    }
+
+    memcpy((out + bl), tmp, leftover);
+    *outl += (bl + leftover);
+    return 1;
+  }
+  default:
+    EVPerr(EVP_F_EVP_ENCRYPTFINAL_CTS, EVP_R_UNSUPPORTED_MODE);
+    return 0;
+  }
+  return 0;
+}
+
  int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
        {
        int n,ret;
        unsigned int i, b, bl;

+       if (ctx->flags & EVP_CIPH_CIPHERTEXT_STEALING)
+               {
+    return EVP_EncryptFinal_cts(ctx, out, outl);
+               }
+
        b=ctx->cipher->block_size;
        OPENSSL_assert(b <= sizeof ctx->buf);
        if (b == 1)
@@ -375,12 +522,24 @@
        return ret;
        }

+int
+EVP_DecryptUpdate_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
+                      const unsigned char *in, int inl)
+{
+  return EVP_EncryptUpdate_cts(ctx, out, outl, in, inl);
+}
+
  int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
             const unsigned char *in, int inl)
        {
        int fix_len;
        unsigned int b;

+       if (ctx->flags & EVP_CIPH_CIPHERTEXT_STEALING)
+               {
+    return EVP_DecryptUpdate_cts(ctx, out, outl, in, inl);
+               }
+
        if (inl == 0)
                {
                *outl=0;
@@ -430,11 +589,103 @@
        return ret;
        }

+int
+EVP_DecryptFinal_cts(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
+{
+  unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
+  int bl = ctx->cipher->block_size;
+  int leftover = 0;
+  *outl = 0;
+
+  if (!ctx->final_used) {
+    EVPerr(EVP_F_EVP_DECRYPTFINAL_CTS, EVP_R_EXPECTING_PREVIOUS_CIPHERTEXT);
+    return 0;
+  }
+  if (ctx->buf_len == 0) {
+    EVPerr(EVP_F_EVP_DECRYPTFINAL_CTS, EVP_R_EXPECTING_PREVIOUS_CIPHERTEXT);
+    return 0;
+  }
+
+  /* handle leftover bytes */
+  leftover = ctx->buf_len;
+
+  switch (EVP_CIPHER_CTX_mode(ctx)) {
+  case EVP_CIPH_ECB_MODE: {
+    /* decrypt => P_n plus C' */
+    if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) {
+      return 0;
+    }
+
+    /* C_n plus C' */
+    memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover));
+    /* decrypt => P_{n-1} */
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) {
+      return 0;
+    }
+
+    memcpy((out + bl), tmp, leftover);
+    *outl += (bl + leftover);
+    return 1;
+  }
+  case EVP_CIPH_CBC_MODE: {
+    int i = 0;
+    unsigned char C_n_minus_2[EVP_MAX_BLOCK_LENGTH];
+
+    memcpy(C_n_minus_2, ctx->iv, bl);
+
+    /* C_n plus 0s in ctx->buf */
+    memset(&(ctx->buf[leftover]), 0, (bl - leftover));
+
+    /* ctx->final is C_{n-1} */
+    /* decrypt => (P_n plus C')'' */
+    if (!(ctx->cipher->do_cipher(ctx, tmp, ctx->final, bl))) {
+      return 0;
+    }
+    /* XOR'ed with C_{n-2} => (P_n plus C')' */
+    for (i = 0; i < bl; i++) {
+      tmp[i] = tmp[i] ^ C_n_minus_2[i];
+    }
+    /* XOR'ed with (C_n plus 0s) => P_n plus C' */
+    for (i = 0; i < bl; i++) {
+      tmp[i] = tmp[i] ^ ctx->buf[i];
+    }
+
+    /* C_n plus C' in ctx->buf */
+    memcpy(&(ctx->buf[leftover]), &(tmp[leftover]), (bl - leftover));
+    /* decrypt => P_{n-1}'' */
+    if (!(ctx->cipher->do_cipher(ctx, out, ctx->buf, bl))) {
+      return 0;
+    }
+    /* XOR'ed with C_{n-1} => P_{n-1}' */
+    for (i = 0; i < bl; i++) {
+      out[i] = out[i] ^ ctx->final[i];
+    }
+    /* XOR'ed with C_{n-2} => P_{n-1} */
+    for (i = 0; i < bl; i++) {
+      out[i] = out[i] ^ C_n_minus_2[i];
+    }
+
+    memcpy((out + bl), tmp, leftover);
+    *outl += (bl + leftover);
+    return 1;
+  }
+  default:
+    EVPerr(EVP_F_EVP_DECRYPTFINAL_CTS, EVP_R_UNSUPPORTED_MODE);
+    return 0;
+  }
+  return 0;
+}
+
  int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
        {
        int i,n;
        unsigned int b;

+       if (ctx->flags & EVP_CIPH_CIPHERTEXT_STEALING)
+               {
+    return EVP_DecryptFinal_cts(ctx, out, outl);
+               }
+
        *outl=0;
        b=ctx->cipher->block_size;
        if (ctx->flags & EVP_CIPH_NO_PADDING)
@@ -531,6 +782,27 @@
        return 1;
        }

+int
+EVP_CIPHER_CTX_set_cts(EVP_CIPHER_CTX *ctx, int cts)
+{
+  switch (EVP_CIPHER_CTX_mode(ctx)) {
+  case EVP_CIPH_ECB_MODE:
+  case EVP_CIPH_CBC_MODE:
+    /* supported */
+    break;
+  default:
+    /* not supported */
+    EVPerr(EVP_F_EVP_CIPHER_CTX_SET_CTS, EVP_R_UNSUPPORTED_MODE);
+    return 0;
+  }
+  if (cts) {
+    ctx->flags |= EVP_CIPH_CIPHERTEXT_STEALING;
+  } else {
+    ctx->flags &= ~EVP_CIPH_CIPHERTEXT_STEALING;
+  }
+  return 1;
+}
+
  int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
 {
        int ret;
Index: crypto/evp/evp_err.c
===================================================================
RCS file: /home/pach/prog/openssl/cvs/openssl/crypto/evp/evp_err.c,v
retrieving revision 1.43
diff -u -r1.43 evp_err.c
--- crypto/evp/evp_err.c        21 Nov 2006 21:29:39 -0000      1.43
+++ crypto/evp/evp_err.c        15 Mar 2007 06:13:20 -0000
@@ -1,6 +1,6 @@
  /* crypto/evp/evp_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2006 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -79,9 +79,12 @@
 {ERR_FUNC(EVP_F_ECKEY_PKEY2PKCS8),     "ECKEY_PKEY2PKCS8"},
 {ERR_FUNC(EVP_F_EVP_CIPHERINIT_EX),    "EVP_CipherInit_ex"},
 {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_CTRL),  "EVP_CIPHER_CTX_ctrl"},
+{ERR_FUNC(EVP_F_EVP_CIPHER_CTX_SET_CTS),       "EVP_CIPHER_CTX_set_cts"},
 {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH),        
"EVP_CIPHER_CTX_set_key_length"},
+{ERR_FUNC(EVP_F_EVP_DECRYPTFINAL_CTS), "EVP_DecryptFinal_cts"},
 {ERR_FUNC(EVP_F_EVP_DECRYPTFINAL_EX),  "EVP_DecryptFinal_ex"},
 {ERR_FUNC(EVP_F_EVP_DIGESTINIT_EX),    "EVP_DigestInit_ex"},
+{ERR_FUNC(EVP_F_EVP_ENCRYPTFINAL_CTS), "EVP_EncryptFinal_cts"},
 {ERR_FUNC(EVP_F_EVP_ENCRYPTFINAL_EX),  "EVP_EncryptFinal_ex"},
 {ERR_FUNC(EVP_F_EVP_MD_CTX_COPY_EX),   "EVP_MD_CTX_copy_ex"},
 {ERR_FUNC(EVP_F_EVP_OPENINIT), "EVP_OpenInit"},
@@ -159,6 +162,8 @@
  {ERR_REASON(EVP_R_EXPECTING_A_DSA_KEY)   ,"expecting a dsa key"},
  {ERR_REASON(EVP_R_EXPECTING_A_ECDSA_KEY) ,"expecting a ecdsa key"},
  {ERR_REASON(EVP_R_EXPECTING_A_EC_KEY)    ,"expecting a ec key"},
+{ERR_REASON(EVP_R_EXPECTING_PREVIOUS_CIPHERTEXT),"expecting previous
ciphertext"},
+{ERR_REASON(EVP_R_EXPECTING_PREVIOUS_PLAINTEXT),"expecting previous
plaintext"},
 {ERR_REASON(EVP_R_INITIALIZATION_ERROR)  ,"initialization error"},
 {ERR_REASON(EVP_R_INPUT_NOT_INITIALIZED) ,"input not initialized"},
 {ERR_REASON(EVP_R_INVALID_DIGEST)        ,"invalid digest"},
@@ -188,6 +193,7 @@
  {ERR_REASON(EVP_R_UNSUPPORTED_KEYLENGTH) ,"unsupported keylength"},
 {ERR_REASON(EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION),"unsupported
key derivation function"},
 {ERR_REASON(EVP_R_UNSUPPORTED_KEY_SIZE)  ,"unsupported key size"},
+{ERR_REASON(EVP_R_UNSUPPORTED_MODE)      ,"unsupported mode"},
  {ERR_REASON(EVP_R_UNSUPPORTED_PRF)       ,"unsupported prf"},
 {ERR_REASON(EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM),"unsupported
private key algorithm"},
 {ERR_REASON(EVP_R_UNSUPPORTED_SALT_TYPE) ,"unsupported salt type"},
Index: crypto/evp/evp_test.c
===================================================================
RCS file: /home/pach/prog/openssl/cvs/openssl/crypto/evp/evp_test.c,v
retrieving revision 1.26
diff -u -r1.26 evp_test.c
--- crypto/evp/evp_test.c       9 Jun 2006 15:44:41 -0000       1.26
+++ crypto/evp/evp_test.c       15 Mar 2007 06:05:13 -0000
@@ -317,6 +317,217 @@
     return 1;
     }

+static int
+test_cts(const char *cipher)
+{
+  const EVP_CIPHER *c;
+  static char key[EVP_MAX_BLOCK_LENGTH];
+  static char iv[EVP_MAX_BLOCK_LENGTH];
+  static char ptext[EVP_MAX_BLOCK_LENGTH * 4];
+  static char ctext[EVP_MAX_BLOCK_LENGTH * 4];
+  static char dptext[EVP_MAX_BLOCK_LENGTH * 4];
+  static int initialized = 0;
+  int i, testlen, blocksize, off;
+
+  c = EVP_get_cipherbyname(cipher);
+  if (!c) {
+    return 0;
+  }
+
+  if (!initialized) {
+    for (i = 0; i < EVP_MAX_BLOCK_LENGTH; i++) {
+      key[i] = i;
+      iv[i] = i + 1;
+    }
+    for (i = 0; i < (EVP_MAX_BLOCK_LENGTH * 4); i++) {
+      ptext[i] = i + 2;
+    }
+
+    initialized = 1;
+  }
+
+  blocksize = c->block_size;
+  for (testlen = (blocksize + 1); testlen < (EVP_MAX_BLOCK_LENGTH * 4);
+       testlen++) {
+    int clen, clen2, dplen, dplen2;
+    EVP_CIPHER_CTX ectx;
+    EVP_CIPHER_CTX dctx;
+
+    EVP_CIPHER_CTX_init(&ectx);
+    if (!EVP_EncryptInit_ex(&ectx, c, NULL, key, iv)) {
+      fprintf(stderr, "EncryptInit failed\n");
+      EXIT(201);
+    }
+    if (!EVP_CIPHER_CTX_set_cts(&ectx, 1)) {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    EVP_CIPHER_CTX_init(&dctx);
+    if (!EVP_DecryptInit_ex(&dctx, c, NULL, key, iv)) {
+      fprintf(stderr, "DecryptInit failed\n");
+      EXIT(203);
+    }
+    if (!EVP_CIPHER_CTX_set_cts(&dctx, 1)) {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    if ((!(ectx.flags & EVP_CIPH_CIPHERTEXT_STEALING))
+        || (!(dctx.flags & EVP_CIPH_CIPHERTEXT_STEALING)))  {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    if (!EVP_EncryptUpdate(&ectx, ctext, &clen, ptext, testlen)) {
+      fprintf(stderr, "EncryptUpdate failed\n");
+      EXIT(204);
+    }
+    if(!EVP_EncryptFinal_ex(&ectx, (ctext + clen), &clen2)) {
+      fprintf(stderr, "EncryptFinal failed\n");
+      EXIT(205);
+    }
+    if ((clen + clen2) != testlen) {
+      fprintf(stderr, "Plaintext len=%d, ciphertext len=%d\n", testlen,
+              (clen + clen2));
+      EXIT(206);
+    }
+    if (!EVP_DecryptUpdate(&dctx, dptext, &dplen, ctext, (clen + clen2))) {
+      fprintf(stderr, "DecryptUpdate failed\n");
+      EXIT(207);
+    }
+    if(!EVP_DecryptFinal_ex(&dctx, (dptext + dplen), &dplen2)) {
+      fprintf(stderr, "DecryptFinal failed\n");
+      EXIT(208);
+    }
+    if ((dplen + dplen2) != testlen) {
+      fprintf(stderr, "Plaintext len=%d, decrypted len=%d\n", testlen,
+              (dplen + dplen2));
+      EXIT(207);
+    }
+
+    if (memcmp(ptext, dptext, testlen)) {
+      fprintf(stderr, "Plaintext != decrypted\n");
+      EXIT(208);
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ectx);
+    EVP_CIPHER_CTX_cleanup(&dctx);
+  }
+
+  /* test update/final with small data segments */
+  {
+    int clen, clen2, dplen, dplen2, tlen;
+    EVP_CIPHER_CTX ectx;
+    EVP_CIPHER_CTX dctx;
+
+    EVP_CIPHER_CTX_init(&ectx);
+    if (!EVP_EncryptInit_ex(&ectx, c, NULL, key, iv)) {
+      fprintf(stderr, "EncryptInit failed\n");
+      EXIT(201);
+    }
+    if (!EVP_CIPHER_CTX_set_cts(&ectx, 1)) {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    EVP_CIPHER_CTX_init(&dctx);
+    if (!EVP_DecryptInit_ex(&dctx, c, NULL, key, iv)) {
+      fprintf(stderr, "DecryptInit failed\n");
+      EXIT(203);
+    }
+    if (!EVP_CIPHER_CTX_set_cts(&dctx, 1)) {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    if ((!(ectx.flags & EVP_CIPH_CIPHERTEXT_STEALING))
+        || (!(dctx.flags & EVP_CIPH_CIPHERTEXT_STEALING)))  {
+      fprintf(stderr, "Setting CTS failed\n");
+      EXIT(202);
+    }
+
+    testlen = EVP_MAX_BLOCK_LENGTH * 2 + 1;
+
+    /* encrypt in chunks of 1,2,2,2,... bytes */
+    if (!EVP_EncryptUpdate(&ectx, ctext, &clen, ptext, 1)) {
+      fprintf(stderr, "EncryptUpdate failed\n");
+      EXIT(204);
+    }
+    off = 1;
+    while ((off + 2) <= (testlen - 1)) {
+      if (!EVP_EncryptUpdate(&ectx, (ctext + clen), &tlen,
+                             (ptext + off), 2)) {
+        fprintf(stderr, "EncryptUpdate failed\n");
+        EXIT(204);
+      }
+      off += 2;
+      clen += tlen;
+    }
+    if (!EVP_EncryptUpdate(&ectx, (ctext + clen), &tlen, (ptext + off),
+                           (testlen - off))) {
+      fprintf(stderr, "EncryptUpdate failed\n");
+      EXIT(204);
+    }
+    clen += tlen;
+
+    if(!EVP_EncryptFinal_ex(&ectx, (ctext + clen), &clen2)) {
+      fprintf(stderr, "EncryptFinal failed\n");
+      EXIT(205);
+    }
+
+    if ((clen + clen2) != testlen) {
+      fprintf(stderr, "Plaintext len=%d, ciphertext len=%d\n", testlen,
+              (clen + clen2));
+      EXIT(206);
+    }
+
+    /* decrypt in chunks of 3,2,2,2,... bytes */
+    if (!EVP_DecryptUpdate(&dctx, dptext, &dplen, ctext, 3)) {
+      fprintf(stderr, "DecryptUpdate failed\n");
+      EXIT(207);
+    }
+
+    off = 3;
+    testlen = clen + clen2;
+    while ((off + 2) <= (testlen - 1)) {
+      if (!EVP_DecryptUpdate(&dctx, (dptext + dplen), &tlen,
+                             (ctext + off), 2)) {
+        fprintf(stderr, "DecryptUpdate failed\n");
+        EXIT(207);
+      }
+      off += 2;
+      dplen += tlen;
+    }
+    if (!EVP_DecryptUpdate(&dctx, (dptext + dplen), &tlen, (ctext + off),
+                           (testlen - off))) {
+      fprintf(stderr, "DecryptUpdate failed\n");
+      EXIT(207);
+    }
+    dplen += tlen;
+
+    if(!EVP_DecryptFinal_ex(&dctx, (dptext + dplen), &dplen2)) {
+      fprintf(stderr, "DecryptFinal failed\n");
+      EXIT(208);
+    }
+
+    if ((dplen + dplen2) != testlen) {
+      fprintf(stderr, "Plaintext len=%d, decrypted len=%d\n", testlen,
+              (dplen + dplen2));
+      EXIT(207);
+    }
+
+    if (memcmp(ptext, dptext, testlen)) {
+      fprintf(stderr, "Plaintext != decrypted\n");
+      EXIT(208);
+    }
+
+    EVP_CIPHER_CTX_cleanup(&ectx);
+    EVP_CIPHER_CTX_cleanup(&dctx);
+  }
+  return 1;
+}
+
 int main(int argc,char **argv)
     {
     const char *szTestFile;
@@ -386,7 +597,16 @@
        } else {
            encdec = atoi(sstrsep(&p,"\n"));
        }
-       
+
+       if (memcmp(key, "TEST_CTS", 8) == 0) {
+           printf("Testing CTS with %s ... ", cipher);
+           if (test_cts(cipher)) {
+        printf("OK\n");
+           } else {
+        printf("failed\n");
+      }
+           continue;
+       }

        kn=convert(key);
        in=convert(iv);
Index: crypto/evp/evptests.txt
===================================================================
RCS file: /home/pach/prog/openssl/cvs/openssl/crypto/evp/evptests.txt,v
retrieving revision 1.11
diff -u -r1.11 evptests.txt
--- crypto/evp/evptests.txt     9 Jun 2006 15:44:42 -0000       1.11
+++ crypto/evp/evptests.txt     15 Mar 2007 06:05:13 -0000
@@ -310,3 +310,14 @@
 
CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:E1C656305ED1A7A6563805746FE03EDC:30C81C46A35CE411E5FBC1191A0A52EF:6BFF6265A6A6B7A535BC65A80B17214E:0
 
CAMELLIA-256-OFB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:41635BE625B48AFC1666DD42A09D96E7:F69F2445DF4F9B17AD2B417BE66C3710:0A4A0404E26AA78A27CB271E8BF3CF20:0

+#cipher:TEST_CTS::::
+AES-128-ECB:TEST_CTS::::
+AES-192-ECB:TEST_CTS::::
+AES-256-ECB:TEST_CTS::::
+AES-128-CBC:TEST_CTS::::
+AES-192-CBC:TEST_CTS::::
+AES-256-CBC:TEST_CTS::::
+DES-ECB:TEST_CTS::::
+DESX-CBC:TEST_CTS::::
+DES-EDE3-CBC:TEST_CTS::::
+


______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [email protected]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to