summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'dev-libs/libgcrypt/files')
-rw-r--r--dev-libs/libgcrypt/files/libgcrypt-1.5.0_beta1-ctr.patch750
1 files changed, 750 insertions, 0 deletions
diff --git a/dev-libs/libgcrypt/files/libgcrypt-1.5.0_beta1-ctr.patch b/dev-libs/libgcrypt/files/libgcrypt-1.5.0_beta1-ctr.patch
new file mode 100644
index 000000000000..840d2eb9c6c5
--- /dev/null
+++ b/dev-libs/libgcrypt/files/libgcrypt-1.5.0_beta1-ctr.patch
@@ -0,0 +1,750 @@
+http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=commitdiff;h=2674140cdfdc59ce5ad0238177da1542f5df6e00
+http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=commitdiff;h=3c18377a55085faf4df745034056bac53565effa
+
+--- cipher/cipher.c
++++ cipher/cipher.c
+@@ -190,6 +190,9 @@
+ void (*cbc_dec)(void *context, unsigned char *iv,
+ void *outbuf_arg, const void *inbuf_arg,
+ unsigned int nblocks);
++ void (*ctr_enc)(void *context, unsigned char *iv,
++ void *outbuf_arg, const void *inbuf_arg,
++ unsigned int nblocks);
+ } bulk;
+
+
+@@ -209,12 +212,16 @@
+ unsigned char iv[MAX_BLOCKSIZE];
+ } u_iv;
+
++ /* The counter for CTR mode. This field is also used by AESWRAP and
++ thus we can't use the U_IV union. */
++ union {
++ cipher_context_alignment_t iv_align;
++ unsigned char ctr[MAX_BLOCKSIZE];
++ } u_ctr;
++
+ unsigned char lastiv[MAX_BLOCKSIZE];
+ int unused; /* Number of unused bytes in the IV. */
+
+- unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */
+-
+-
+ /* What follows are two contexts of the cipher in use. The first
+ one needs to be aligned well enough for the cipher operation
+ whereas the second one is a copy created by cipher_setkey and
+@@ -814,6 +821,7 @@
+ h->bulk.cfb_dec = _gcry_aes_cfb_dec;
+ h->bulk.cbc_enc = _gcry_aes_cbc_enc;
+ h->bulk.cbc_dec = _gcry_aes_cbc_dec;
++ h->bulk.ctr_enc = _gcry_aes_ctr_enc;
+ break;
+ #endif /*USE_AES*/
+
+@@ -936,7 +944,7 @@
+ memset (&c->marks, 0, sizeof c->marks);
+ memset (c->u_iv.iv, 0, c->cipher->blocksize);
+ memset (c->lastiv, 0, c->cipher->blocksize);
+- memset (c->ctr, 0, c->cipher->blocksize);
++ memset (c->u_ctr.ctr, 0, c->cipher->blocksize);
+ }
+
+
+@@ -1441,35 +1449,50 @@
+ const unsigned char *inbuf, unsigned int inbuflen)
+ {
+ unsigned int n;
+- unsigned char tmp[MAX_BLOCKSIZE];
+ int i;
+ unsigned int blocksize = c->cipher->blocksize;
++ unsigned int nblocks;
+
+ if (outbuflen < inbuflen)
+ return GPG_ERR_BUFFER_TOO_SHORT;
+
+- if ((inbuflen % blocksize))
+- return GPG_ERR_INV_LENGTH;
++ /* Use a bulk method if available. */
++ nblocks = inbuflen / blocksize;
++ if (nblocks && c->bulk.ctr_enc)
++ {
++ c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
++ inbuf += nblocks * blocksize;
++ outbuf += nblocks * blocksize;
++ inbuflen -= nblocks * blocksize;
++ }
+
+- for (n=0; n < inbuflen; n++)
++ /* If we don't have a bulk method use the standard method. We also
++ use this method for the a remaining partial block. */
++ if (inbuflen)
+ {
+- if ((n % blocksize) == 0)
+- {
+- c->cipher->encrypt (&c->context.c, tmp, c->ctr);
++ unsigned char tmp[MAX_BLOCKSIZE];
+
+- for (i = blocksize; i > 0; i--)
+- {
+- c->ctr[i-1]++;
+- if (c->ctr[i-1] != 0)
+- break;
+- }
+- }
++ for (n=0; n < inbuflen; n++)
++ {
++ if ((n % blocksize) == 0)
++ {
++ c->cipher->encrypt (&c->context.c, tmp, c->u_ctr.ctr);
++
++ for (i = blocksize; i > 0; i--)
++ {
++ c->u_ctr.ctr[i-1]++;
++ if (c->u_ctr.ctr[i-1] != 0)
++ break;
++ }
++ }
++
++ /* XOR input with encrypted counter and store in output. */
++ outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
++ }
+
+- /* XOR input with encrypted counter and store in output. */
+- outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
++ wipememory (tmp, sizeof tmp);
+ }
+
+- wipememory (tmp, sizeof tmp);
+ return 0;
+ }
+
+@@ -1517,7 +1540,7 @@
+
+ r = outbuf;
+ a = outbuf; /* We store A directly in OUTBUF. */
+- b = c->ctr; /* B is also used to concatenate stuff. */
++ b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
+
+ /* If an IV has been set we use that IV as the Alternative Initial
+ Value; if it has not been set we use the standard value. */
+@@ -1593,7 +1616,7 @@
+
+ r = outbuf;
+ a = c->lastiv; /* We use c->LASTIV as buffer for A. */
+- b = c->ctr; /* B is also used to concatenate stuff. */
++ b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */
+
+ /* Copy the inbuf to the outbuf and save A. */
+ memcpy (a, inbuf, 8);
+@@ -1861,9 +1884,9 @@
+ _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
+ {
+ if (ctr && ctrlen == hd->cipher->blocksize)
+- memcpy (hd->ctr, ctr, hd->cipher->blocksize);
++ memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+ else if (!ctr || !ctrlen)
+- memset (hd->ctr, 0, hd->cipher->blocksize);
++ memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+ else
+ return gpg_error (GPG_ERR_INV_ARG);
+ return 0;
+@@ -1923,9 +1946,9 @@
+
+ case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */
+ if (buffer && buflen == h->cipher->blocksize)
+- memcpy (h->ctr, buffer, h->cipher->blocksize);
++ memcpy (h->u_ctr.ctr, buffer, h->cipher->blocksize);
+ else if (buffer == NULL || buflen == 0)
+- memset (h->ctr, 0, h->cipher->blocksize);
++ memset (h->u_ctr.ctr, 0, h->cipher->blocksize);
+ else
+ rc = GPG_ERR_INV_ARG;
+ break;
+--- cipher/rijndael.c
++++ cipher/rijndael.c
+@@ -90,9 +90,7 @@
+ #endif
+
+
+-static const char *selftest(void);
+-
+-
++
+ /* Our context object. */
+ typedef struct
+ {
+@@ -144,6 +142,11 @@
+ do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \
+ "pxor %%xmm1, %%xmm1\n" :: ); \
+ } while (0)
++# define aesni_cleanup_2_4() \
++ do { asm volatile ("pxor %%xmm2, %%xmm2\n\t" \
++ "pxor %%xmm3, %%xmm3\n" \
++ "pxor %%xmm4, %%xmm4\n":: ); \
++ } while (0)
+ #else
+ # define aesni_prepare() do { } while (0)
+ # define aesni_cleanup() do { } while (0)
+@@ -154,6 +157,23 @@
+ #include "rijndael-tables.h"
+
+
++
++/* Function prototypes. */
++#ifdef USE_AESNI
++/* We don't want to inline these functions to help gcc allocate enough
++ registers. */
++static void do_aesni_ctr (const RIJNDAEL_context *ctx, unsigned char *ctr,
++ unsigned char *b, const unsigned char *a)
++ __attribute__ ((__noinline__));
++static void do_aesni_ctr_4 (const RIJNDAEL_context *ctx, unsigned char *ctr,
++ unsigned char *b, const unsigned char *a)
++ __attribute__ ((__noinline__));
++#endif /*USE_AESNI*/
++
++static const char *selftest(void);
++
++
++
+ /* Perform the key setup. */
+ static gcry_err_code_t
+ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen)
+@@ -272,7 +292,7 @@
+ else if (ctx->use_aesni && ctx->rounds == 10)
+ {
+ /* Note: This code works for AES-128 but it is not much better
+- than than using the standard key schedule. We disable it for
++ than using the standard key schedule. We disable it for
+ now and don't put any effort into implementing this for
+ AES-192 and AES-256. */
+ asm volatile ("movl %[key], %%esi\n\t"
+@@ -860,6 +880,239 @@
+ #undef aesenclast_xmm1_xmm0
+ }
+
++/* Perform a CTR encryption round using the counter CTR and the input
++ block A. Write the result to the output block B and update CTR.
++ CTR needs to be a 16 byte aligned little-endian value. */
++static void
++do_aesni_ctr (const RIJNDAEL_context *ctx,
++ unsigned char *ctr, unsigned char *b, const unsigned char *a)
++{
++#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
++#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
++ static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
++ { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
++
++ asm volatile ("movdqa %[ctr], %%xmm0\n\t" /* xmm0, xmm2 := CTR */
++ "movaps %%xmm0, %%xmm2\n\t"
++ "mov $1, %%esi\n\t" /* xmm2++ (big-endian) */
++ "movd %%esi, %%xmm1\n\t"
++ "pshufb %[mask], %%xmm2\n\t"
++ "paddq %%xmm1, %%xmm2\n\t"
++ "pshufb %[mask], %%xmm2\n\t"
++ "movdqa %%xmm2, %[ctr]\n" /* Update CTR. */
++
++ "movl %[key], %%esi\n\t" /* esi := keyschenc */
++ "movdqa (%%esi), %%xmm1\n\t" /* xmm1 := key[0] */
++ "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
++ "movdqa 0x10(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x20(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x30(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x40(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x50(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x60(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x70(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x80(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0x90(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0xa0(%%esi), %%xmm1\n\t"
++ "cmp $10, %[rounds]\n\t"
++ "jz .Lenclast%=\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0xb0(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0xc0(%%esi), %%xmm1\n\t"
++ "cmp $12, %[rounds]\n\t"
++ "jz .Lenclast%=\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0xd0(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ "movdqa 0xe0(%%esi), %%xmm1\n"
++
++ ".Lenclast%=:\n\t"
++ aesenclast_xmm1_xmm0
++ "movdqu %[src], %%xmm1\n\t" /* xmm1 := input */
++ "pxor %%xmm1, %%xmm0\n\t" /* EncCTR ^= input */
++ "movdqu %%xmm0, %[dst]" /* Store EncCTR. */
++
++ : [ctr] "+m" (*ctr), [dst] "=m" (*b)
++ : [src] "m" (*a),
++ [key] "g" (ctx->keyschenc),
++ [rounds] "g" (ctx->rounds),
++ [mask] "m" (*be_mask)
++ : "%esi", "cc", "memory");
++#undef aesenc_xmm1_xmm0
++#undef aesenclast_xmm1_xmm0
++}
++
++
++/* Four blocks at a time variant of do_aesni_ctr. */
++static void
++do_aesni_ctr_4 (const RIJNDAEL_context *ctx,
++ unsigned char *ctr, unsigned char *b, const unsigned char *a)
++{
++#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t"
++#define aesenc_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd1\n\t"
++#define aesenc_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd9\n\t"
++#define aesenc_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xe1\n\t"
++#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t"
++#define aesenclast_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd1\n\t"
++#define aesenclast_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd9\n\t"
++#define aesenclast_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xe1\n\t"
++
++ static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
++ { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
++
++ /* Register usage:
++ esi keyschedule
++ xmm0 CTR-0
++ xmm1 temp / round key
++ xmm2 CTR-1
++ xmm3 CTR-2
++ xmm4 CTR-3
++ xmm5 temp
++ */
++
++ asm volatile ("movdqa %[ctr], %%xmm0\n\t" /* xmm0, xmm2 := CTR */
++ "movaps %%xmm0, %%xmm2\n\t"
++ "mov $1, %%esi\n\t" /* xmm1 := 1 */
++ "movd %%esi, %%xmm1\n\t"
++ "pshufb %[mask], %%xmm2\n\t" /* xmm2 := le(xmm2) */
++ "paddq %%xmm1, %%xmm2\n\t" /* xmm2++ */
++ "movaps %%xmm2, %%xmm3\n\t" /* xmm3 := xmm2 */
++ "paddq %%xmm1, %%xmm3\n\t" /* xmm3++ */
++ "movaps %%xmm3, %%xmm4\n\t" /* xmm4 := xmm3 */
++ "paddq %%xmm1, %%xmm4\n\t" /* xmm4++ */
++ "movaps %%xmm4, %%xmm5\n\t" /* xmm5 := xmm4 */
++ "paddq %%xmm1, %%xmm5\n\t" /* xmm5++ */
++ "pshufb %[mask], %%xmm2\n\t" /* xmm2 := be(xmm2) */
++ "pshufb %[mask], %%xmm3\n\t" /* xmm3 := be(xmm3) */
++ "pshufb %[mask], %%xmm4\n\t" /* xmm4 := be(xmm4) */
++ "pshufb %[mask], %%xmm5\n\t" /* xmm5 := be(xmm5) */
++ "movdqa %%xmm5, %[ctr]\n" /* Update CTR. */
++
++ "movl %[key], %%esi\n\t" /* esi := keyschenc */
++ "movdqa (%%esi), %%xmm1\n\t" /* xmm1 := key[0] */
++ "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */
++ "pxor %%xmm1, %%xmm2\n\t" /* xmm2 ^= key[0] */
++ "pxor %%xmm1, %%xmm3\n\t" /* xmm3 ^= key[0] */
++ "pxor %%xmm1, %%xmm4\n\t" /* xmm4 ^= key[0] */
++ "movdqa 0x10(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x20(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x30(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x40(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x50(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x60(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x70(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x80(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0x90(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0xa0(%%esi), %%xmm1\n\t"
++ "cmp $10, %[rounds]\n\t"
++ "jz .Lenclast%=\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0xb0(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0xc0(%%esi), %%xmm1\n\t"
++ "cmp $12, %[rounds]\n\t"
++ "jz .Lenclast%=\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0xd0(%%esi), %%xmm1\n\t"
++ aesenc_xmm1_xmm0
++ aesenc_xmm1_xmm2
++ aesenc_xmm1_xmm3
++ aesenc_xmm1_xmm4
++ "movdqa 0xe0(%%esi), %%xmm1\n"
++
++ ".Lenclast%=:\n\t"
++ aesenclast_xmm1_xmm0
++ aesenclast_xmm1_xmm2
++ aesenclast_xmm1_xmm3
++ aesenclast_xmm1_xmm4
++
++ "movdqu %[src], %%xmm1\n\t" /* Get block 1. */
++ "pxor %%xmm1, %%xmm0\n\t" /* EncCTR-1 ^= input */
++ "movdqu %%xmm0, %[dst]\n\t" /* Store block 1 */
++
++ "movdqu (16)%[src], %%xmm1\n\t" /* Get block 2. */
++ "pxor %%xmm1, %%xmm2\n\t" /* EncCTR-2 ^= input */
++ "movdqu %%xmm2, (16)%[dst]\n\t" /* Store block 2. */
++
++ "movdqu (32)%[src], %%xmm1\n\t" /* Get block 3. */
++ "pxor %%xmm1, %%xmm3\n\t" /* EncCTR-3 ^= input */
++ "movdqu %%xmm3, (32)%[dst]\n\t" /* Store block 3. */
++
++ "movdqu (48)%[src], %%xmm1\n\t" /* Get block 4. */
++ "pxor %%xmm1, %%xmm4\n\t" /* EncCTR-4 ^= input */
++ "movdqu %%xmm4, (48)%[dst]" /* Store block 4. */
++
++ : [ctr] "+m" (*ctr), [dst] "=m" (*b)
++ : [src] "m" (*a),
++ [key] "g" (ctx->keyschenc),
++ [rounds] "g" (ctx->rounds),
++ [mask] "m" (*be_mask)
++ : "%esi", "cc", "memory");
++#undef aesenc_xmm1_xmm0
++#undef aesenc_xmm1_xmm2
++#undef aesenc_xmm1_xmm3
++#undef aesenc_xmm1_xmm4
++#undef aesenclast_xmm1_xmm0
++#undef aesenclast_xmm1_xmm2
++#undef aesenclast_xmm1_xmm3
++#undef aesenclast_xmm1_xmm4
++}
++
+
+ static void
+ do_aesni (RIJNDAEL_context *ctx, int decrypt_flag,
+@@ -1014,6 +1267,69 @@
+
+ _gcry_burn_stack (48 + 2*sizeof(int));
+ }
++
++
++/* Bulk encryption of complete blocks in CTR mode. Caller needs to
++ make sure that CTR is aligned on a 16 byte boundary if AESNI; the
++ minimum alignment is for an u32. This function is only intended
++ for the bulk encryption feature of cipher.c. CTR is expected to be
++ of size BLOCKSIZE. */
++void
++_gcry_aes_ctr_enc (void *context, unsigned char *ctr,
++ void *outbuf_arg, const void *inbuf_arg,
++ unsigned int nblocks)
++{
++ RIJNDAEL_context *ctx = context;
++ unsigned char *outbuf = outbuf_arg;
++ const unsigned char *inbuf = inbuf_arg;
++ unsigned char *p;
++ int i;
++
++ if (0)
++ ;
++#ifdef USE_AESNI
++ else if (ctx->use_aesni)
++ {
++ aesni_prepare ();
++ for ( ;nblocks > 3 ; nblocks -= 4 )
++ {
++ do_aesni_ctr_4 (ctx, ctr, outbuf, inbuf);
++ outbuf += 4*BLOCKSIZE;
++ inbuf += 4*BLOCKSIZE;
++ }
++ for ( ;nblocks; nblocks-- )
++ {
++ do_aesni_ctr (ctx, ctr, outbuf, inbuf);
++ outbuf += BLOCKSIZE;
++ inbuf += BLOCKSIZE;
++ }
++ aesni_cleanup ();
++ aesni_cleanup_2_4 ();
++ }
++#endif /*USE_AESNI*/
++ else
++ {
++ union { unsigned char x1[16]; u32 x32[4]; } tmp;
++
++ for ( ;nblocks; nblocks-- )
++ {
++ /* Encrypt the counter. */
++ do_encrypt_aligned (ctx, tmp.x1, ctr);
++ /* XOR the input with the encrypted counter and store in output. */
++ for (p=tmp.x1, i=0; i < BLOCKSIZE; i++)
++ *outbuf++ = (*p++ ^= *inbuf++);
++ /* Increment the counter. */
++ for (i = BLOCKSIZE; i > 0; i--)
++ {
++ ctr[i-1]++;
++ if (ctr[i-1])
++ break;
++ }
++ }
++ }
++
++ _gcry_burn_stack (48 + 2*sizeof(int));
++}
+
+
+
+--- src/cipher.h
++++ src/cipher.h
+@@ -53,6 +53,9 @@
+ void _gcry_aes_cbc_dec (void *context, unsigned char *iv,
+ void *outbuf_arg, const void *inbuf_arg,
+ unsigned int nblocks);
++void _gcry_aes_ctr_enc (void *context, unsigned char *ctr,
++ void *outbuf_arg, const void *inbuf_arg,
++ unsigned int nblocks);
+
+
+ /*-- dsa.c --*/
+--- tests/basic.c
++++ tests/basic.c
+@@ -69,6 +69,22 @@
+ }
+
+ static void
++mismatch (const void *expected, size_t expectedlen,
++ const void *computed, size_t computedlen)
++{
++ const unsigned char *p;
++
++ fprintf (stderr, "expected:");
++ for (p = expected; expectedlen; p++, expectedlen--)
++ fprintf (stderr, " %02x", *p);
++ fprintf (stderr, "\ncomputed:");
++ for (p = computed; computedlen; p++, computedlen--)
++ fprintf (stderr, " %02x", *p);
++ fprintf (stderr, "\n");
++}
++
++
++static void
+ die (const char *format, ...)
+ {
+ va_list arg_ptr;
+@@ -349,8 +365,7 @@
+ unsigned char plaintext[MAX_DATA_LEN];
+ int inlen;
+ char out[MAX_DATA_LEN];
+- }
+- data[MAX_DATA_LEN];
++ } data[5];
+ } tv[] =
+ {
+ /* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
+@@ -369,6 +384,8 @@
+ { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+ 16,
+ "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1\x79\x21\x70\xa0\xf3\x00\x9c\xee" },
++
++ { "", 0, "" }
+ }
+ },
+ { GCRY_CIPHER_AES192,
+@@ -387,6 +404,7 @@
+ { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+ 16,
+ "\x4f\x78\xa7\xf6\xd2\x98\x09\x58\x5a\x97\xda\xec\x58\xc6\xb0\x50" },
++ { "", 0, "" }
+ }
+ },
+ { GCRY_CIPHER_AES256,
+@@ -404,7 +422,80 @@
+ "\x2b\x09\x30\xda\xa2\x3d\xe9\x4c\xe8\x70\x17\xba\x2d\x84\x98\x8d" },
+ { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+ 16,
+- "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6\x13\xc2\xdd\x08\x45\x79\x41\xa6" }
++ "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6\x13\xc2\xdd\x08\x45\x79\x41\xa6" },
++ { "", 0, "" }
++ }
++ },
++ /* Some truncation tests. With a truncated second block and
++ also with a single truncated block. */
++ { GCRY_CIPHER_AES,
++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
++ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
++ 16,
++ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
++ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
++ 15,
++ "\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
++ {"", 0, "" }
++ }
++ },
++ { GCRY_CIPHER_AES,
++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
++ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
++ 16,
++ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
++ {"\xae",
++ 1,
++ "\x98" },
++ {"", 0, "" }
++ }
++ },
++ { GCRY_CIPHER_AES,
++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
++ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17",
++ 15,
++ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6" },
++ {"", 0, "" }
++ }
++ },
++ { GCRY_CIPHER_AES,
++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
++ {{"\x6b",
++ 1,
++ "\x87" },
++ {"", 0, "" }
++ }
++ },
++#if USE_CAST5
++ /* A selfmade test vector using an 64 bit block cipher. */
++ { GCRY_CIPHER_CAST5,
++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8",
++ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
++ 16,
++ "\xe8\xa7\xac\x68\xca\xca\xa0\x20\x10\xcb\x1b\xcc\x79\x2c\xc4\x48" },
++ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c",
++ 8,
++ "\x16\xe8\x72\x77\xb0\x98\x29\x68" },
++ {"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
++ 8,
++ "\x9a\xb3\xa8\x03\x3b\xb4\x14\xba" },
++ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\xa1\x00",
++ 10,
++ "\x31\x5e\xd3\xfb\x1b\x8d\xd1\xf9\xb0\x83" },
++ { "", 0, "" }
++ }
++ },
++#endif /*USE_CAST5*/
++ { 0,
++ "",
++ "",
++ {
++ {"", 0, "" }
+ }
+ }
+ };
+@@ -417,6 +508,9 @@
+ fprintf (stderr, " Starting CTR cipher checks.\n");
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
++ if (!tv[i].algo)
++ continue;
++
+ err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
+ if (!err)
+ err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
+@@ -485,7 +579,11 @@
+ }
+
+ if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
+- fail ("aes-ctr, encrypt mismatch entry %d:%d\n", i, j);
++ {
++ fail ("aes-ctr, encrypt mismatch entry %d:%d\n", i, j);
++ mismatch (tv[i].data[j].out, tv[i].data[j].inlen,
++ out, tv[i].data[j].inlen);
++ }
+
+ err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
+ if (err)
+@@ -498,7 +596,11 @@
+ }
+
+ if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+- fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
++ {
++ fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
++ mismatch (tv[i].data[j].plaintext, tv[i].data[j].inlen,
++ out, tv[i].data[j].inlen);
++ }
+
+ }
+
+@@ -509,18 +611,6 @@
+ if (err)
+ fail ("aes-ctr, encryption failed for valid input");
+
+- err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+- "1234567890123456", 15);
+- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+- fail ("aes-ctr, too short input returned wrong error: %s\n",
+- gpg_strerror (err));
+-
+- err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+- "12345678901234567", 17);
+- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+- fail ("aes-ctr, too long input returned wrong error: %s\n",
+- gpg_strerror (err));
+-
+ err = gcry_cipher_encrypt (hde, out, 15,
+ "1234567890123456", 16);
+ if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
+@@ -545,18 +635,6 @@
+ if (err)
+ fail ("aes-ctr, decryption failed for valid input");
+
+- err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
+- "1234567890123456", 15);
+- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+- fail ("aes-ctr, too short input returned wrong error: %s\n",
+- gpg_strerror (err));
+-
+- err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
+- "12345678901234567", 17);
+- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
+- fail ("aes-ctr, too long input returned wrong error: %s\n",
+- gpg_strerror (err));
+-
+ err = gcry_cipher_decrypt (hde, out, 15,
+ "1234567890123456", 16);
+ if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)