Renesas / SecureDweet
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     #include <wolfcrypt/src/misc.c>
00044 #endif
00045 
00046 #ifdef CHACHA_AEAD_TEST
00047     #include <stdio.h>
00048 #endif
00049 
00050 #ifdef BIG_ENDIAN_ORDER
00051     #define LITTLE32(x) ByteReverseWord32(x)
00052 #else
00053     #define LITTLE32(x) (x)
00054 #endif
00055 
00056 /* Number of rounds */
00057 #define ROUNDS  20
00058 
00059 #define U32C(v) (v##U)
00060 #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
00061 #define U8TO32_LITTLE(p) LITTLE32(((word32*)(p))[0])
00062 
00063 #define ROTATE(v,c) rotlFixed(v, c)
00064 #define XOR(v,w)    ((v) ^ (w))
00065 #define PLUS(v,w)   (U32V((v) + (w)))
00066 #define PLUSONE(v)  (PLUS((v),1))
00067 
00068 #define QUARTERROUND(a,b,c,d) \
00069   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
00070   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
00071   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
00072   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
00073 
00074 
00075 /**
00076   * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
00077   * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
00078   */
00079 int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
00080 {
00081     word32 temp[3];       /* used for alignment of memory */
00082 
00083 #ifdef CHACHA_AEAD_TEST
00084     word32 i;
00085     printf("NONCE : ");
00086     for (i = 0; i < 12; i++) {
00087         printf("%02x", inIv[i]);
00088     }
00089     printf("\n\n");
00090 #endif
00091 
00092     if (ctx == NULL)
00093         return BAD_FUNC_ARG;
00094 
00095     XMEMCPY(temp, inIv, 12);
00096 
00097     ctx->X[12] = counter;           /* block counter */
00098     ctx->X[13] = LITTLE32(temp[0]); /* fixed variable from nonce */
00099     ctx->X[14] = LITTLE32(temp[1]); /* counter from nonce */
00100     ctx->X[15] = LITTLE32(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 wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
00114 {
00115     const word32* constants;
00116     const byte*   k;
00117 
00118 #ifdef XSTREAM_ALIGN
00119     word32 alignKey[8];
00120 #endif
00121 
00122     if (ctx == NULL)
00123         return BAD_FUNC_ARG;
00124 
00125     if (keySz != 16 && keySz != 32)
00126         return BAD_FUNC_ARG;
00127 
00128 #ifdef XSTREAM_ALIGN
00129     if ((wolfssl_word)key % 4) {
00130         WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
00131         XMEMCPY(alignKey, key, keySz);
00132         k = (byte*)alignKey;
00133     }
00134     else {
00135         k = key;
00136     }
00137 #else
00138     k = key;
00139 #endif /* XSTREAM_ALIGN */
00140 
00141 #ifdef CHACHA_AEAD_TEST
00142     word32 i;
00143     printf("ChaCha key used :\n");
00144     for (i = 0; i < keySz; i++) {
00145         printf("%02x", key[i]);
00146         if ((i + 1) % 8 == 0)
00147            printf("\n");
00148     }
00149     printf("\n\n");
00150 #endif
00151 
00152     ctx->X[4] = U8TO32_LITTLE(k +  0);
00153     ctx->X[5] = U8TO32_LITTLE(k +  4);
00154     ctx->X[6] = U8TO32_LITTLE(k +  8);
00155     ctx->X[7] = U8TO32_LITTLE(k + 12);
00156     if (keySz == 32) {
00157         k += 16;
00158         constants = sigma;
00159     }
00160     else {
00161         constants = tau;
00162     }
00163     ctx->X[ 8] = U8TO32_LITTLE(k +  0);
00164     ctx->X[ 9] = U8TO32_LITTLE(k +  4);
00165     ctx->X[10] = U8TO32_LITTLE(k +  8);
00166     ctx->X[11] = U8TO32_LITTLE(k + 12);
00167     ctx->X[ 0] = constants[0];
00168     ctx->X[ 1] = constants[1];
00169     ctx->X[ 2] = constants[2];
00170     ctx->X[ 3] = constants[3];
00171 
00172     return 0;
00173 }
00174 
00175 /**
00176   * Converts word into bytes with rotations having been done.
00177   */
00178 static INLINE void wc_Chacha_wordtobyte(word32 output[16], const word32 input[16])
00179 {
00180     word32 x[16];
00181     word32 i;
00182 
00183     for (i = 0; i < 16; i++) {
00184         x[i] = input[i];
00185     }
00186 
00187     for (i = (ROUNDS); i > 0; i -= 2) {
00188         QUARTERROUND(0, 4,  8, 12)
00189         QUARTERROUND(1, 5,  9, 13)
00190         QUARTERROUND(2, 6, 10, 14)
00191         QUARTERROUND(3, 7, 11, 15)
00192         QUARTERROUND(0, 5, 10, 15)
00193         QUARTERROUND(1, 6, 11, 12)
00194         QUARTERROUND(2, 7,  8, 13)
00195         QUARTERROUND(3, 4,  9, 14)
00196     }
00197 
00198     for (i = 0; i < 16; i++) {
00199         x[i] = PLUS(x[i], input[i]);
00200     }
00201 
00202     for (i = 0; i < 16; i++) {
00203         output[i] = LITTLE32(x[i]);
00204     }
00205 }
00206 
00207 /**
00208   * Encrypt a stream of bytes
00209   */
00210 static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
00211                                  word32 bytes)
00212 {
00213     byte*  output;
00214     word32 temp[16]; /* used to make sure aligned */
00215     word32 i;
00216 
00217     output = (byte*)temp;
00218 
00219     if (!bytes) return;
00220     for (;;) {
00221         wc_Chacha_wordtobyte(temp, ctx->X);
00222         ctx->X[12] = PLUSONE(ctx->X[12]);
00223         if (bytes <= 64) {
00224             for (i = 0; i < bytes; ++i) {
00225                 c[i] = m[i] ^ output[i];
00226             }
00227             return;
00228         }
00229         for (i = 0; i < 64; ++i) {
00230             c[i] = m[i] ^ output[i];
00231         }
00232         bytes -= 64;
00233         c += 64;
00234         m += 64;
00235     }
00236 }
00237 
00238 /**
00239   * API to encrypt/decrypt a message of any size.
00240   */
00241 int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input, word32 msglen)
00242 {
00243     if (ctx == NULL)
00244         return BAD_FUNC_ARG;
00245 
00246     wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
00247 
00248     return 0;
00249 }
00250 
00251 #endif /* HAVE_CHACHA*/
00252 
00253