LCOV - code coverage report
Current view: top level - cipher - chacha20.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 153 0.0 %
Date: 2016-12-15 12:59:22 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /* chacha20.c  -  Bernstein's ChaCha20 cipher
       2             :  * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
       3             :  *
       4             :  * This file is part of Libgcrypt.
       5             :  *
       6             :  * Libgcrypt is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser general Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * Libgcrypt is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  *
      19             :  * For a description of the algorithm, see:
      20             :  *   http://cr.yp.to/chacha.html
      21             :  */
      22             : 
      23             : /* The code is based on salsa20.c and public-domain ChaCha implementations:
      24             :  *  chacha-ref.c version 20080118
      25             :  *  D. J. Bernstein
      26             :  *  Public domain.
      27             :  * and
      28             :  *  Andrew Moon
      29             :  *  https://github.com/floodyberry/chacha-opt
      30             :  */
      31             : 
      32             : 
      33             : #include <config.h>
      34             : #include <stdio.h>
      35             : #include <stdlib.h>
      36             : #include <string.h>
      37             : #include "types.h"
      38             : #include "g10lib.h"
      39             : #include "cipher.h"
      40             : #include "bufhelp.h"
      41             : 
      42             : 
      43             : #define CHACHA20_MIN_KEY_SIZE 16        /* Bytes.  */
      44             : #define CHACHA20_MAX_KEY_SIZE 32        /* Bytes.  */
      45             : #define CHACHA20_BLOCK_SIZE   64        /* Bytes.  */
      46             : #define CHACHA20_MIN_IV_SIZE   8        /* Bytes.  */
      47             : #define CHACHA20_MAX_IV_SIZE  12        /* Bytes.  */
      48             : #define CHACHA20_CTR_SIZE     16        /* Bytes.  */
      49             : #define CHACHA20_INPUT_LENGTH (CHACHA20_BLOCK_SIZE / 4)
      50             : 
      51             : /* USE_SSE2 indicates whether to compile with Intel SSE2 code. */
      52             : #undef USE_SSE2
      53             : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
      54             :     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
      55             : # define USE_SSE2 1
      56             : #endif
      57             : 
      58             : /* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */
      59             : #undef USE_SSSE3
      60             : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
      61             :     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
      62             :     defined(HAVE_GCC_INLINE_ASM_SSSE3)
      63             : # define USE_SSSE3 1
      64             : #endif
      65             : 
      66             : /* USE_AVX2 indicates whether to compile with Intel AVX2 code. */
      67             : #undef USE_AVX2
      68             : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
      69             :     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
      70             :     defined(ENABLE_AVX2_SUPPORT)
      71             : # define USE_AVX2 1
      72             : #endif
      73             : 
      74             : /* USE_NEON indicates whether to enable ARM NEON assembly code. */
      75             : #undef USE_NEON
      76             : #ifdef ENABLE_NEON_SUPPORT
      77             : # if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \
      78             :      && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \
      79             :      && defined(HAVE_GCC_INLINE_ASM_NEON)
      80             : #  define USE_NEON 1
      81             : # endif
      82             : #endif /*ENABLE_NEON_SUPPORT*/
      83             : 
      84             : 
      85             : struct CHACHA20_context_s;
      86             : 
      87             : 
      88             : /* Assembly implementations use SystemV ABI, ABI conversion and additional
      89             :  * stack to store XMM6-XMM15 needed on Win64. */
      90             : #undef ASM_FUNC_ABI
      91             : #undef ASM_EXTRA_STACK
      92             : #if (defined(USE_SSE2) || defined(USE_SSSE3) || defined(USE_AVX2)) && \
      93             :     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)
      94             : # define ASM_FUNC_ABI __attribute__((sysv_abi))
      95             : # define ASM_EXTRA_STACK (10 * 16)
      96             : #else
      97             : # define ASM_FUNC_ABI
      98             : # define ASM_EXTRA_STACK 0
      99             : #endif
     100             : 
     101             : 
     102             : typedef unsigned int (* chacha20_blocks_t)(u32 *state, const byte *src,
     103             :                                            byte *dst,
     104             :                                            size_t bytes) ASM_FUNC_ABI;
     105             : 
     106             : typedef struct CHACHA20_context_s
     107             : {
     108             :   u32 input[CHACHA20_INPUT_LENGTH];
     109             :   u32 pad[CHACHA20_INPUT_LENGTH];
     110             :   chacha20_blocks_t blocks;
     111             :   unsigned int unused; /* bytes in the pad.  */
     112             : } CHACHA20_context_t;
     113             : 
     114             : 
     115             : #ifdef USE_SSE2
     116             : 
     117             : unsigned int _gcry_chacha20_amd64_sse2_blocks(u32 *state, const byte *in,
     118             :                                               byte *out,
     119             :                                               size_t bytes) ASM_FUNC_ABI;
     120             : 
     121             : #endif /* USE_SSE2 */
     122             : 
     123             : #ifdef USE_SSSE3
     124             : 
     125             : unsigned int _gcry_chacha20_amd64_ssse3_blocks(u32 *state, const byte *in,
     126             :                                                byte *out,
     127             :                                                size_t bytes) ASM_FUNC_ABI;
     128             : 
     129             : #endif /* USE_SSSE3 */
     130             : 
     131             : #ifdef USE_AVX2
     132             : 
     133             : unsigned int _gcry_chacha20_amd64_avx2_blocks(u32 *state, const byte *in,
     134             :                                               byte *out,
     135             :                                               size_t bytes) ASM_FUNC_ABI;
     136             : 
     137             : #endif /* USE_AVX2 */
     138             : 
     139             : #ifdef USE_NEON
     140             : 
     141             : unsigned int _gcry_chacha20_armv7_neon_blocks(u32 *state, const byte *in,
     142             :                                               byte *out,
     143             :                                               size_t bytes) ASM_FUNC_ABI;
     144             : 
     145             : #endif /* USE_NEON */
     146             : 
     147             : 
     148             : static void chacha20_setiv (void *context, const byte * iv, size_t ivlen);
     149             : static const char *selftest (void);
     150             : 
     151             : 
     152             : 
     153             : #define QROUND(a,b,c,d)         \
     154             :   do {                          \
     155             :     a += b; d = rol(d ^ a, 16); \
     156             :     c += d; b = rol(b ^ c, 12); \
     157             :     a += b; d = rol(d ^ a, 8);  \
     158             :     c += d; b = rol(b ^ c, 7);  \
     159             :   } while (0)
     160             : 
     161             : #define QOUT(ai, bi, ci, di) \
     162             :   DO_OUT(ai); DO_OUT(bi); DO_OUT(ci); DO_OUT(di)
     163             : 
     164             : 
     165             : #ifndef USE_SSE2
     166             : ASM_FUNC_ABI static unsigned int
     167             : chacha20_blocks (u32 *state, const byte *src, byte *dst, size_t bytes)
     168             : {
     169             :   u32 pad[CHACHA20_INPUT_LENGTH];
     170             :   u32 inp[CHACHA20_INPUT_LENGTH];
     171             :   unsigned int i;
     172             : 
     173             :   /* Note: 'bytes' must be multiple of 64 and not zero. */
     174             : 
     175             :   inp[0] = state[0];
     176             :   inp[1] = state[1];
     177             :   inp[2] = state[2];
     178             :   inp[3] = state[3];
     179             :   inp[4] = state[4];
     180             :   inp[5] = state[5];
     181             :   inp[6] = state[6];
     182             :   inp[7] = state[7];
     183             :   inp[8] = state[8];
     184             :   inp[9] = state[9];
     185             :   inp[10] = state[10];
     186             :   inp[11] = state[11];
     187             :   inp[12] = state[12];
     188             :   inp[13] = state[13];
     189             :   inp[14] = state[14];
     190             :   inp[15] = state[15];
     191             : 
     192             :   do
     193             :     {
     194             :       /* First round. */
     195             :       pad[0] = inp[0];
     196             :       pad[4] = inp[4];
     197             :       pad[8] = inp[8];
     198             :       pad[12] = inp[12];
     199             :       QROUND (pad[0], pad[4], pad[8], pad[12]);
     200             :       pad[1] = inp[1];
     201             :       pad[5] = inp[5];
     202             :       pad[9] = inp[9];
     203             :       pad[13] = inp[13];
     204             :       QROUND (pad[1], pad[5], pad[9], pad[13]);
     205             :       pad[2] = inp[2];
     206             :       pad[6] = inp[6];
     207             :       pad[10] = inp[10];
     208             :       pad[14] = inp[14];
     209             :       QROUND (pad[2], pad[6], pad[10], pad[14]);
     210             :       pad[3] = inp[3];
     211             :       pad[7] = inp[7];
     212             :       pad[11] = inp[11];
     213             :       pad[15] = inp[15];
     214             :       QROUND (pad[3], pad[7], pad[11], pad[15]);
     215             : 
     216             :       QROUND (pad[0], pad[5], pad[10], pad[15]);
     217             :       QROUND (pad[1], pad[6], pad[11], pad[12]);
     218             :       QROUND (pad[2], pad[7], pad[8], pad[13]);
     219             :       QROUND (pad[3], pad[4], pad[9], pad[14]);
     220             : 
     221             :       for (i = 2; i < 20 - 2; i += 2)
     222             :       {
     223             :         QROUND (pad[0], pad[4], pad[8], pad[12]);
     224             :         QROUND (pad[1], pad[5], pad[9], pad[13]);
     225             :         QROUND (pad[2], pad[6], pad[10], pad[14]);
     226             :         QROUND (pad[3], pad[7], pad[11], pad[15]);
     227             : 
     228             :         QROUND (pad[0], pad[5], pad[10], pad[15]);
     229             :         QROUND (pad[1], pad[6], pad[11], pad[12]);
     230             :         QROUND (pad[2], pad[7], pad[8], pad[13]);
     231             :         QROUND (pad[3], pad[4], pad[9], pad[14]);
     232             :       }
     233             : 
     234             :       QROUND (pad[0], pad[4], pad[8], pad[12]);
     235             :       QROUND (pad[1], pad[5], pad[9], pad[13]);
     236             :       QROUND (pad[2], pad[6], pad[10], pad[14]);
     237             :       QROUND (pad[3], pad[7], pad[11], pad[15]);
     238             : 
     239             :       if (src)
     240             :         {
     241             : #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, \
     242             :                                  (pad[idx] + inp[idx]) ^ \
     243             :                                   buf_get_le32(src + (idx) * 4))
     244             :           /* Last round. */
     245             :           QROUND (pad[0], pad[5], pad[10], pad[15]);
     246             :           QOUT(0, 5, 10, 15);
     247             :           QROUND (pad[1], pad[6], pad[11], pad[12]);
     248             :           QOUT(1, 6, 11, 12);
     249             :           QROUND (pad[2], pad[7], pad[8], pad[13]);
     250             :           QOUT(2, 7, 8, 13);
     251             :           QROUND (pad[3], pad[4], pad[9], pad[14]);
     252             :           QOUT(3, 4, 9, 14);
     253             : #undef DO_OUT
     254             :         }
     255             :       else
     256             :         {
     257             : #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, pad[idx] + inp[idx])
     258             :           /* Last round. */
     259             :           QROUND (pad[0], pad[5], pad[10], pad[15]);
     260             :           QOUT(0, 5, 10, 15);
     261             :           QROUND (pad[1], pad[6], pad[11], pad[12]);
     262             :           QOUT(1, 6, 11, 12);
     263             :           QROUND (pad[2], pad[7], pad[8], pad[13]);
     264             :           QOUT(2, 7, 8, 13);
     265             :           QROUND (pad[3], pad[4], pad[9], pad[14]);
     266             :           QOUT(3, 4, 9, 14);
     267             : #undef DO_OUT
     268             :         }
     269             : 
     270             :       /* Update counter. */
     271             :       inp[13] += (!++inp[12]);
     272             : 
     273             :       bytes -= CHACHA20_BLOCK_SIZE;
     274             :       dst += CHACHA20_BLOCK_SIZE;
     275             :       src += (src) ? CHACHA20_BLOCK_SIZE : 0;
     276             :     }
     277             :   while (bytes >= CHACHA20_BLOCK_SIZE);
     278             : 
     279             :   state[12] = inp[12];
     280             :   state[13] = inp[13];
     281             : 
     282             :   /* burn_stack */
     283             :   return (2 * CHACHA20_INPUT_LENGTH * sizeof(u32) + 6 * sizeof(void *));
     284             : }
     285             : #endif /*!USE_SSE2*/
     286             : 
     287             : #undef QROUND
     288             : #undef QOUT
     289             : 
     290             : 
     291             : static unsigned int
     292           0 : chacha20_core(u32 *dst, struct CHACHA20_context_s *ctx)
     293             : {
     294           0 :   return ctx->blocks(ctx->input, NULL, (byte *)dst, CHACHA20_BLOCK_SIZE)
     295           0 :          + ASM_EXTRA_STACK;
     296             : }
     297             : 
     298             : 
     299             : static void
     300           0 : chacha20_keysetup (CHACHA20_context_t * ctx, const byte * key,
     301             :                    unsigned int keylen)
     302             : {
     303             :   /* These constants are the little endian encoding of the string
     304             :      "expand 32-byte k".  For the 128 bit variant, the "32" in that
     305             :      string will be fixed up to "16".  */
     306           0 :   ctx->input[0] = 0x61707865;        /* "apxe"  */
     307           0 :   ctx->input[1] = 0x3320646e;        /* "3 dn"  */
     308           0 :   ctx->input[2] = 0x79622d32;        /* "yb-2"  */
     309           0 :   ctx->input[3] = 0x6b206574;        /* "k et"  */
     310             : 
     311           0 :   ctx->input[4] = buf_get_le32 (key + 0);
     312           0 :   ctx->input[5] = buf_get_le32 (key + 4);
     313           0 :   ctx->input[6] = buf_get_le32 (key + 8);
     314           0 :   ctx->input[7] = buf_get_le32 (key + 12);
     315             : 
     316           0 :   if (keylen == CHACHA20_MAX_KEY_SIZE) /* 256 bits */
     317             :     {
     318           0 :       ctx->input[8] = buf_get_le32 (key + 16);
     319           0 :       ctx->input[9] = buf_get_le32 (key + 20);
     320           0 :       ctx->input[10] = buf_get_le32 (key + 24);
     321           0 :       ctx->input[11] = buf_get_le32 (key + 28);
     322             :     }
     323             :   else /* 128 bits */
     324             :     {
     325           0 :       ctx->input[8] = ctx->input[4];
     326           0 :       ctx->input[9] = ctx->input[5];
     327           0 :       ctx->input[10] = ctx->input[6];
     328           0 :       ctx->input[11] = ctx->input[7];
     329             : 
     330           0 :       ctx->input[1] -= 0x02000000;        /* Change to "1 dn".  */
     331           0 :       ctx->input[2] += 0x00000004;        /* Change to "yb-6".  */
     332             :     }
     333           0 : }
     334             : 
     335             : 
     336             : static void
     337           0 : chacha20_ivsetup (CHACHA20_context_t * ctx, const byte * iv, size_t ivlen)
     338             : {
     339           0 :   if (ivlen == CHACHA20_CTR_SIZE)
     340             :     {
     341           0 :       ctx->input[12] = buf_get_le32 (iv + 0);
     342           0 :       ctx->input[13] = buf_get_le32 (iv + 4);
     343           0 :       ctx->input[14] = buf_get_le32 (iv + 8);
     344           0 :       ctx->input[15] = buf_get_le32 (iv + 12);
     345             :     }
     346           0 :   else if (ivlen == CHACHA20_MAX_IV_SIZE)
     347             :     {
     348           0 :       ctx->input[12] = 0;
     349           0 :       ctx->input[13] = buf_get_le32 (iv + 0);
     350           0 :       ctx->input[14] = buf_get_le32 (iv + 4);
     351           0 :       ctx->input[15] = buf_get_le32 (iv + 8);
     352             :     }
     353           0 :   else if (ivlen == CHACHA20_MIN_IV_SIZE)
     354             :     {
     355           0 :       ctx->input[12] = 0;
     356           0 :       ctx->input[13] = 0;
     357           0 :       ctx->input[14] = buf_get_le32 (iv + 0);
     358           0 :       ctx->input[15] = buf_get_le32 (iv + 4);
     359             :     }
     360             :   else
     361             :     {
     362           0 :       ctx->input[12] = 0;
     363           0 :       ctx->input[13] = 0;
     364           0 :       ctx->input[14] = 0;
     365           0 :       ctx->input[15] = 0;
     366             :     }
     367           0 : }
     368             : 
     369             : 
     370             : static gcry_err_code_t
     371           0 : chacha20_do_setkey (CHACHA20_context_t * ctx,
     372             :                     const byte * key, unsigned int keylen)
     373             : {
     374             :   static int initialized;
     375             :   static const char *selftest_failed;
     376           0 :   unsigned int features = _gcry_get_hw_features ();
     377             : 
     378           0 :   if (!initialized)
     379             :     {
     380           0 :       initialized = 1;
     381           0 :       selftest_failed = selftest ();
     382           0 :       if (selftest_failed)
     383           0 :         log_error ("CHACHA20 selftest failed (%s)\n", selftest_failed);
     384             :     }
     385           0 :   if (selftest_failed)
     386           0 :     return GPG_ERR_SELFTEST_FAILED;
     387             : 
     388           0 :   if (keylen != CHACHA20_MAX_KEY_SIZE && keylen != CHACHA20_MIN_KEY_SIZE)
     389           0 :     return GPG_ERR_INV_KEYLEN;
     390             : 
     391             : #ifdef USE_SSE2
     392           0 :   ctx->blocks = _gcry_chacha20_amd64_sse2_blocks;
     393             : #else
     394             :   ctx->blocks = chacha20_blocks;
     395             : #endif
     396             : 
     397             : #ifdef USE_SSSE3
     398           0 :   if (features & HWF_INTEL_SSSE3)
     399           0 :     ctx->blocks = _gcry_chacha20_amd64_ssse3_blocks;
     400             : #endif
     401             : #ifdef USE_AVX2
     402           0 :   if (features & HWF_INTEL_AVX2)
     403           0 :     ctx->blocks = _gcry_chacha20_amd64_avx2_blocks;
     404             : #endif
     405             : #ifdef USE_NEON
     406             :   if (features & HWF_ARM_NEON)
     407             :     ctx->blocks = _gcry_chacha20_armv7_neon_blocks;
     408             : #endif
     409             : 
     410             :   (void)features;
     411             : 
     412           0 :   chacha20_keysetup (ctx, key, keylen);
     413             : 
     414             :   /* We default to a zero nonce.  */
     415           0 :   chacha20_setiv (ctx, NULL, 0);
     416             : 
     417           0 :   return 0;
     418             : }
     419             : 
     420             : 
     421             : static gcry_err_code_t
     422           0 : chacha20_setkey (void *context, const byte * key, unsigned int keylen)
     423             : {
     424           0 :   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
     425           0 :   gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen);
     426           0 :   _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
     427           0 :   return rc;
     428             : }
     429             : 
     430             : 
     431             : static void
     432           0 : chacha20_setiv (void *context, const byte * iv, size_t ivlen)
     433             : {
     434           0 :   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
     435             : 
     436             :   /* draft-nir-cfrg-chacha20-poly1305-02 defines 96-bit and 64-bit nonce. */
     437           0 :   if (iv && ivlen != CHACHA20_MAX_IV_SIZE && ivlen != CHACHA20_MIN_IV_SIZE
     438           0 :       && ivlen != CHACHA20_CTR_SIZE)
     439           0 :     log_info ("WARNING: chacha20_setiv: bad ivlen=%u\n", (u32) ivlen);
     440             : 
     441           0 :   if (iv && (ivlen == CHACHA20_MAX_IV_SIZE || ivlen == CHACHA20_MIN_IV_SIZE
     442           0 :              || ivlen == CHACHA20_CTR_SIZE))
     443           0 :     chacha20_ivsetup (ctx, iv, ivlen);
     444             :   else
     445           0 :     chacha20_ivsetup (ctx, NULL, 0);
     446             : 
     447             :   /* Reset the unused pad bytes counter.  */
     448           0 :   ctx->unused = 0;
     449           0 : }
     450             : 
     451             : 
     452             : 
     453             : /* Note: This function requires LENGTH > 0.  */
     454             : static void
     455           0 : chacha20_do_encrypt_stream (CHACHA20_context_t * ctx,
     456             :                             byte * outbuf, const byte * inbuf, size_t length)
     457             : {
     458           0 :   unsigned int nburn, burn = 0;
     459             : 
     460           0 :   if (ctx->unused)
     461             :     {
     462           0 :       unsigned char *p = (void *) ctx->pad;
     463             :       size_t n;
     464             : 
     465           0 :       gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
     466             : 
     467           0 :       n = ctx->unused;
     468           0 :       if (n > length)
     469           0 :         n = length;
     470           0 :       buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
     471           0 :       length -= n;
     472           0 :       outbuf += n;
     473           0 :       inbuf += n;
     474           0 :       ctx->unused -= n;
     475           0 :       if (!length)
     476           0 :         return;
     477           0 :       gcry_assert (!ctx->unused);
     478             :     }
     479             : 
     480           0 :   if (length >= CHACHA20_BLOCK_SIZE)
     481             :     {
     482           0 :       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
     483           0 :       size_t bytes = nblocks * CHACHA20_BLOCK_SIZE;
     484           0 :       burn = ctx->blocks(ctx->input, inbuf, outbuf, bytes);
     485           0 :       length -= bytes;
     486           0 :       outbuf += bytes;
     487           0 :       inbuf  += bytes;
     488             :     }
     489             : 
     490           0 :   if (length > 0)
     491             :     {
     492           0 :       nburn = chacha20_core (ctx->pad, ctx);
     493           0 :       burn = nburn > burn ? nburn : burn;
     494             : 
     495           0 :       buf_xor (outbuf, inbuf, ctx->pad, length);
     496           0 :       ctx->unused = CHACHA20_BLOCK_SIZE - length;
     497             :     }
     498             : 
     499           0 :   _gcry_burn_stack (burn);
     500             : }
     501             : 
     502             : 
     503             : static void
     504           0 : chacha20_encrypt_stream (void *context, byte * outbuf, const byte * inbuf,
     505             :                          size_t length)
     506             : {
     507           0 :   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
     508             : 
     509           0 :   if (length)
     510           0 :     chacha20_do_encrypt_stream (ctx, outbuf, inbuf, length);
     511           0 : }
     512             : 
     513             : 
     514             : static const char *
     515           0 : selftest (void)
     516             : {
     517             :   byte ctxbuf[sizeof(CHACHA20_context_t) + 15];
     518             :   CHACHA20_context_t *ctx;
     519             :   byte scratch[127 + 1];
     520             :   byte buf[512 + 64 + 4];
     521             :   int i;
     522             : 
     523             :   /* From draft-strombergson-chacha-test-vectors */
     524             :   static byte key_1[] = {
     525             :     0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78,
     526             :     0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35,
     527             :     0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb,
     528             :     0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d
     529             :   };
     530             :   static const byte nonce_1[] =
     531             :     { 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21 };
     532             :   static const byte plaintext_1[127] = {
     533             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     534             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     535             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     536             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     537             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     538             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     539             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     540             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     541             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     542             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     543             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     544             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     545             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     546             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     547             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     548             :     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     549             :   };
     550             :   static const byte ciphertext_1[127] = {
     551             :     0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9,
     552             :     0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06,
     553             :     0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00,
     554             :     0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf,
     555             :     0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd,
     556             :     0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f,
     557             :     0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f,
     558             :     0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92,
     559             :     0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9,
     560             :     0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36,
     561             :     0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1,
     562             :     0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38,
     563             :     0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea,
     564             :     0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0,
     565             :     0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27,
     566             :     0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33
     567             :   };
     568             : 
     569             :   /* 16-byte alignment required for amd64 implementation. */
     570           0 :   ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15);
     571             : 
     572           0 :   chacha20_setkey (ctx, key_1, sizeof key_1);
     573           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     574           0 :   scratch[sizeof (scratch) - 1] = 0;
     575           0 :   chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1);
     576           0 :   if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
     577           0 :     return "ChaCha20 encryption test 1 failed.";
     578           0 :   if (scratch[sizeof (scratch) - 1])
     579           0 :     return "ChaCha20 wrote too much.";
     580           0 :   chacha20_setkey (ctx, key_1, sizeof (key_1));
     581           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     582           0 :   chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1);
     583           0 :   if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
     584           0 :     return "ChaCha20 decryption test 1 failed.";
     585             : 
     586           0 :   for (i = 0; i < sizeof buf; i++)
     587           0 :     buf[i] = i;
     588           0 :   chacha20_setkey (ctx, key_1, sizeof key_1);
     589           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     590             :   /*encrypt */
     591           0 :   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
     592             :   /*decrypt */
     593           0 :   chacha20_setkey (ctx, key_1, sizeof key_1);
     594           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     595           0 :   chacha20_encrypt_stream (ctx, buf, buf, 1);
     596           0 :   chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1);
     597           0 :   chacha20_encrypt_stream (ctx, buf + (sizeof buf) - 1,
     598             :                            buf + (sizeof buf) - 1, 1);
     599           0 :   for (i = 0; i < sizeof buf; i++)
     600           0 :     if (buf[i] != (byte) i)
     601           0 :       return "ChaCha20 encryption test 2 failed.";
     602             : 
     603           0 :   chacha20_setkey (ctx, key_1, sizeof key_1);
     604           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     605             :   /* encrypt */
     606           0 :   for (i = 0; i < sizeof buf; i++)
     607           0 :     chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1);
     608             :   /* decrypt */
     609           0 :   chacha20_setkey (ctx, key_1, sizeof key_1);
     610           0 :   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
     611           0 :   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
     612           0 :   for (i = 0; i < sizeof buf; i++)
     613           0 :     if (buf[i] != (byte) i)
     614           0 :       return "ChaCha20 encryption test 3 failed.";
     615             : 
     616           0 :   return NULL;
     617             : }
     618             : 
     619             : 
     620             : gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = {
     621             :   GCRY_CIPHER_CHACHA20,
     622             :   {0, 0},                       /* flags */
     623             :   "CHACHA20",                   /* name */
     624             :   NULL,                         /* aliases */
     625             :   NULL,                         /* oids */
     626             :   1,                            /* blocksize in bytes. */
     627             :   CHACHA20_MAX_KEY_SIZE * 8,    /* standard key length in bits. */
     628             :   sizeof (CHACHA20_context_t),
     629             :   chacha20_setkey,
     630             :   NULL,
     631             :   NULL,
     632             :   chacha20_encrypt_stream,
     633             :   chacha20_encrypt_stream,
     634             :   NULL,
     635             :   NULL,
     636             :   chacha20_setiv
     637             : };

Generated by: LCOV version 1.12