wolf SSL / wolfSSL-TLS13-Beta

Fork of wolfSSL by wolf SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chacha.c Source File

chacha.c

00001 /* chacha.c
00002  *
00003  * Copyright (C) 2006-2016 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSL.
00006  *
00007  * wolfSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
00020  *
00021  *  based from
00022  *  chacha-ref.c version 20080118
00023  *  D. J. Bernstein
00024  *  Public domain.
00025  */
00026 
00027 
00028 
00029 #ifdef HAVE_CONFIG_H
00030     #include <config.h>
00031 #endif
00032 
00033 #include <wolfssl/wolfcrypt/settings.h>
00034 
00035 #ifdef HAVE_CHACHA
00036 
00037 #include <wolfssl/wolfcrypt/chacha.h>
00038 #include <wolfssl/wolfcrypt/error-crypt.h>
00039 #include <wolfssl/wolfcrypt/logging.h>
00040 #ifdef NO_INLINE
00041     #include <wolfssl/wolfcrypt/misc.h>
00042 #else
00043     #define WOLFSSL_MISC_INCLUDED
00044     #include <wolfcrypt/src/misc.c>
00045 #endif
00046 
00047 #ifdef CHACHA_AEAD_TEST
00048     #include <stdio.h>
00049 #endif
00050 
00051 #ifdef BIG_ENDIAN_ORDER
00052     #define LITTLE32(x) ByteReverseWord32(x)
00053 #else
00054     #define LITTLE32(x) (x)
00055 #endif
00056 
00057 /* Number of rounds */
00058 #define ROUNDS  20
00059 
00060 #define U32C(v) (v##U)
00061 #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
00062 #define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])
00063 
00064 #define ROTATE(v,c) rotlFixed(v, c)
00065 #define XOR(v,w)    ((v) ^ (w))
00066 #define PLUS(v,w)   (U32V((v) + (w)))
00067 #define PLUSONE(v)  (PLUS((v),1))
00068 
00069 #define QUARTERROUND(a,b,c,d) \
00070   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
00071   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
00072   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
00073   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
00074 
00075 
00076 /**
00077   * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
00078   * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
00079   */
00080 int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
00081 {
00082     word32 temp[CHACHA_IV_WORDS];/* used for alignment of memory */
00083 
00084 #ifdef CHACHA_AEAD_TEST
00085     word32 i;
00086     printf("NONCE : ");
00087     for (i = 0; i < CHACHA_IV_BYTES; i++) {
00088         printf("%02x", inIv[i]);
00089     }
00090     printf("\n\n");
00091 #endif
00092 
00093     if (ctx == NULL)
00094         return BAD_FUNC_ARG;
00095 
00096     XMEMCPY(temp, inIv, CHACHA_IV_BYTES);
00097 
00098     ctx->X[CHACHA_IV_BYTES+0] = counter;           /* block counter */
00099     ctx->X[CHACHA_IV_BYTES+1] = LITTLE32(temp[0]); /* fixed variable from nonce */
00100     ctx->X[CHACHA_IV_BYTES+2] = LITTLE32(temp[1]); /* counter from nonce */
00101     ctx->X[CHACHA_IV_BYTES+3] = LITTLE32(temp[2]); /* counter from nonce */
00102 
00103     return 0;
00104 }
00105 
00106 /* "expand 32-byte k" as unsigned 32 byte */
00107 static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
00108 /* "expand 16-byte k" as unsigned 16 byte */
00109 static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
00110 
00111 /**
00112   * Key setup. 8 word iv (nonce)
00113   */
00114 int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
00115 {
00116     const word32* constants;
00117     const byte*   k;
00118 
00119 #ifdef XSTREAM_ALIGN
00120     word32 alignKey[8];
00121 #endif
00122 
00123     if (ctx == NULL)
00124         return BAD_FUNC_ARG;
00125 
00126     if (keySz != 16 && keySz != 32)
00127         return BAD_FUNC_ARG;
00128 
00129 #ifdef XSTREAM_ALIGN
00130     if ((wolfssl_word)key % 4) {
00131         WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
00132         XMEMCPY(alignKey, key, keySz);
00133         k = (byte*)alignKey;
00134     }
00135     else {
00136         k = key;
00137     }
00138 #else
00139     k = key;
00140 #endif /* XSTREAM_ALIGN */
00141 
00142 #ifdef CHACHA_AEAD_TEST
00143     word32 i;
00144     printf("ChaCha key used :\n");
00145     for (i = 0; i < keySz; i++) {
00146         printf("%02x", key[i]);
00147         if ((i + 1) % 8 == 0)
00148            printf("\n");
00149     }
00150     printf("\n\n");
00151 #endif
00152 
00153     ctx->X[4] = U8TO32_LITTLE(k +  0);
00154     ctx->X[5] = U8TO32_LITTLE(k +  4);
00155     ctx->X[6] = U8TO32_LITTLE(k +  8);
00156     ctx->X[7] = U8TO32_LITTLE(k + 12);
00157     if (keySz == 32) {
00158         k += 16;
00159         constants = sigma;
00160     }
00161     else {
00162         constants = tau;
00163     }
00164     ctx->X[ 8] = U8TO32_LITTLE(k +  0);
00165     ctx->X[ 9] = U8TO32_LITTLE(k +  4);
00166     ctx->X[10] = U8TO32_LITTLE(k +  8);
00167     ctx->X[11] = U8TO32_LITTLE(k + 12);
00168     ctx->X[ 0] = constants[0];
00169     ctx->X[ 1] = constants[1];
00170     ctx->X[ 2] = constants[2];
00171     ctx->X[ 3] = constants[3];
00172 
00173     return 0;
00174 }
00175 
00176 /**
00177   * Converts word into bytes with rotations having been done.
00178   */
00179 static INLINE void wc_Chacha_wordtobyte(word32 output[CHACHA_CHUNK_WORDS],
00180     const word32 input[CHACHA_CHUNK_WORDS])
00181 {
00182     word32 x[CHACHA_CHUNK_WORDS];
00183     word32 i;
00184 
00185     for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
00186         x[i] = input[i];
00187     }
00188 
00189     for (i = (ROUNDS); i > 0; i -= 2) {
00190         QUARTERROUND(0, 4,  8, 12)
00191         QUARTERROUND(1, 5,  9, 13)
00192         QUARTERROUND(2, 6, 10, 14)
00193         QUARTERROUND(3, 7, 11, 15)
00194         QUARTERROUND(0, 5, 10, 15)
00195         QUARTERROUND(1, 6, 11, 12)
00196         QUARTERROUND(2, 7,  8, 13)
00197         QUARTERROUND(3, 4,  9, 14)
00198     }
00199 
00200     for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
00201         x[i] = PLUS(x[i], input[i]);
00202     }
00203 
00204     for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
00205         output[i] = LITTLE32(x[i]);
00206     }
00207 }
00208 
00209 /**
00210   * Encrypt a stream of bytes
00211   */
00212 static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
00213                                  word32 bytes)
00214 {
00215     byte*  output;
00216     word32 temp[CHACHA_CHUNK_WORDS]; /* used to make sure aligned */
00217     word32 i;
00218 
00219     output = (byte*)temp;
00220 
00221     if (!bytes) return;
00222     for (;;) {
00223         wc_Chacha_wordtobyte(temp, ctx->X);
00224         ctx->X[CHACHA_IV_BYTES] = PLUSONE(ctx->X[CHACHA_IV_BYTES]);
00225         if (bytes <= CHACHA_CHUNK_BYTES) {
00226             for (i = 0; i < bytes; ++i) {
00227                 c[i] = m[i] ^ output[i];
00228             }
00229             return;
00230         }
00231         for (i = 0; i < CHACHA_CHUNK_BYTES; ++i) {
00232             c[i] = m[i] ^ output[i];
00233         }
00234         bytes -= CHACHA_CHUNK_BYTES;
00235         c += CHACHA_CHUNK_BYTES;
00236         m += CHACHA_CHUNK_BYTES;
00237     }
00238 }
00239 
00240 /**
00241   * API to encrypt/decrypt a message of any size.
00242   */
00243 int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input, word32 msglen)
00244 {
00245     if (ctx == NULL)
00246         return BAD_FUNC_ARG;
00247 
00248     wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
00249 
00250     return 0;
00251 }
00252 
00253 #endif /* HAVE_CHACHA*/
00254 
00255