Dependents:   HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL HTTPClient-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-2014 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL 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  * CyaSSL 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-1301, USA
00020  *  
00021  *  based from
00022  *  chacha-ref.c version 20080118
00023  *  D. J. Bernstein
00024  *  Public domain.
00025  */
00026  
00027 
00028 #ifdef HAVE_CONFIG_H
00029     #include <config.h>
00030 #endif
00031 
00032 #include <cyassl/ctaocrypt/settings.h>
00033 
00034 #ifdef HAVE_CHACHA
00035 
00036 #include <cyassl/ctaocrypt/chacha.h>
00037 #include <cyassl/ctaocrypt/error-crypt.h>
00038 #include <cyassl/ctaocrypt/logging.h>
00039 #ifdef NO_INLINE
00040     #include <cyassl/ctaocrypt/misc.h>
00041 #else
00042     #include <ctaocrypt/src/misc.c>
00043 #endif
00044 
00045 #ifdef CHACHA_AEAD_TEST
00046     #include <stdio.h>
00047 #endif
00048 
00049 #ifdef BIG_ENDIAN_ORDER
00050     #define LITTLE32(x) ByteReverseWord32(x)
00051 #else
00052     #define LITTLE32(x) (x)
00053 #endif
00054 
00055 /* Number of rounds */
00056 #define ROUNDS  20
00057 
00058 #define U32C(v) (v##U)
00059 #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
00060 #define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])
00061 
00062 #define ROTATE(v,c) rotlFixed(v, c)
00063 #define XOR(v,w)    ((v) ^ (w))
00064 #define PLUS(v,w)   (U32V((v) + (w)))
00065 #define PLUSONE(v)  (PLUS((v),1))
00066 
00067 #define QUARTERROUND(a,b,c,d) \
00068   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
00069   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
00070   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
00071   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
00072 
00073 
00074 /**
00075   * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
00076   * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
00077   */
00078 int Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
00079 {
00080     word32 temp[3];       /* used for alignment of memory */
00081     XMEMSET(temp, 0, 12);
00082 
00083     if (ctx == NULL)
00084         return BAD_FUNC_ARG;
00085 
00086 #ifdef CHACHA_AEAD_TEST
00087     word32 i;
00088     printf("NONCE : ");
00089     for (i = 0; i < 12; i++) {
00090         printf("%02x", inIv[i]);
00091     }
00092     printf("\n\n");
00093 #endif
00094 
00095     XMEMCPY(temp, inIv, 12);
00096 
00097     ctx->X[12] = counter; /* block counter */
00098     ctx->X[13] = temp[0]; /* fixed variable from nonce */
00099     ctx->X[14] = temp[1]; /* counter from nonce */
00100     ctx->X[15] = temp[2]; /* counter from nonce */
00101     
00102     return 0;
00103 }
00104 
00105 /* "expand 32-byte k" as unsigned 32 byte */
00106 static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
00107 /* "expand 16-byte k" as unsigned 16 byte */
00108 static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
00109 
00110 /**
00111   * Key setup. 8 word iv (nonce)
00112   */
00113 int Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
00114 {
00115     const word32* constants;
00116     const byte*   k;
00117 
00118     if (ctx == NULL)
00119         return BAD_FUNC_ARG;
00120 
00121 #ifdef XSTREAM_ALIGN
00122     word32 alignKey[keySz / 4];
00123     if ((cyassl_word)key % 4) {
00124         CYASSL_MSG("ChachaSetKey unaligned key");
00125         XMEMCPY(alignKey, key, sizeof(alignKey));
00126         k = (byte*)alignKey;
00127     }
00128     else {
00129         k = key;
00130     }
00131 #else
00132     k = key;
00133 #endif /* XSTREAM_ALIGN */
00134 
00135 #ifdef CHACHA_AEAD_TEST
00136     word32 i;
00137     printf("ChaCha key used :\n");
00138     for (i = 0; i < keySz; i++) {
00139         printf("%02x", key[i]);
00140         if ((i + 1) % 8 == 0)
00141            printf("\n"); 
00142     }
00143     printf("\n\n");
00144 #endif
00145 
00146     ctx->X[4] = U8TO32_LITTLE(k +  0);
00147     ctx->X[5] = U8TO32_LITTLE(k +  4);
00148     ctx->X[6] = U8TO32_LITTLE(k +  8);
00149     ctx->X[7] = U8TO32_LITTLE(k + 12);
00150     if (keySz == 32) {
00151         k += 16;
00152         constants = sigma;
00153     }
00154     else {
00155         /* key size of 128 */
00156         if (keySz != 16)
00157             return BAD_FUNC_ARG;
00158 
00159         constants = tau;
00160     }
00161     ctx->X[ 8] = U8TO32_LITTLE(k +  0);
00162     ctx->X[ 9] = U8TO32_LITTLE(k +  4);
00163     ctx->X[10] = U8TO32_LITTLE(k +  8);
00164     ctx->X[11] = U8TO32_LITTLE(k + 12);
00165     ctx->X[ 0] = U8TO32_LITTLE(constants + 0);
00166     ctx->X[ 1] = U8TO32_LITTLE(constants + 1);
00167     ctx->X[ 2] = U8TO32_LITTLE(constants + 2);
00168     ctx->X[ 3] = U8TO32_LITTLE(constants + 3);
00169 
00170     return 0;
00171 }
00172 
00173 /**
00174   * Converts word into bytes with rotations having been done.
00175   */
00176 static INLINE void Chacha_wordtobyte(word32 output[16], const word32 input[16])
00177 {
00178     word32 x[16];
00179     word32 i;
00180 
00181     for (i = 0; i < 16; i++) {
00182         x[i] = input[i];
00183     }
00184 
00185     for (i = (ROUNDS); i > 0; i -= 2) {
00186         QUARTERROUND(0, 4,  8, 12)
00187         QUARTERROUND(1, 5,  9, 13)
00188         QUARTERROUND(2, 6, 10, 14)
00189         QUARTERROUND(3, 7, 11, 15)
00190         QUARTERROUND(0, 5, 10, 15)
00191         QUARTERROUND(1, 6, 11, 12)
00192         QUARTERROUND(2, 7,  8, 13)
00193         QUARTERROUND(3, 4,  9, 14)
00194     }
00195 
00196     for (i = 0; i < 16; i++) {
00197         x[i] = PLUS(x[i], input[i]);
00198     }
00199 
00200     for (i = 0; i < 16; i++) {
00201         output[i] = LITTLE32(x[i]);
00202     }
00203 }
00204 
00205 /**
00206   * Encrypt a stream of bytes
00207   */
00208 static void Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
00209                                  word32 bytes)
00210 {
00211     byte*  output;
00212     word32 temp[16]; /* used to make sure aligned */
00213     word32 i;
00214 
00215     output = (byte*)temp;
00216 
00217     if (!bytes) return;
00218     for (;;) {
00219         Chacha_wordtobyte(temp, ctx->X);
00220         ctx->X[12] = PLUSONE(ctx->X[12]);
00221         if (bytes <= 64) {
00222             for (i = 0; i < bytes; ++i) {
00223                 c[i] = m[i] ^ output[i];
00224             }
00225             return;
00226         }
00227         for (i = 0; i < 64; ++i) {
00228             c[i] = m[i] ^ output[i];
00229         }
00230         bytes -= 64;
00231         c += 64;
00232         m += 64;
00233     }
00234 }
00235 
00236 /**
00237   * API to encrypt/decrypt a message of any size.
00238   */
00239 int Chacha_Process(ChaCha* ctx, byte* output, const byte* input, word32 msglen)
00240 {
00241     if (ctx == NULL)
00242         return BAD_FUNC_ARG;
00243 
00244     Chacha_encrypt_bytes(ctx, input, output, msglen);
00245 
00246     return 0;
00247 }
00248 
00249 #endif /* HAVE_CHACHA*/
00250