diff options
Diffstat (limited to 'dev-libs/libgcrypt/files')
-rw-r--r-- | dev-libs/libgcrypt/files/libgcrypt-1.5.0_beta1-ctr.patch | 750 |
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) |