wolf SSL / wolfSSL-TLS13-Beta

Fork of wolfSSL by wolf SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chacha20_poly1305.c Source File

chacha20_poly1305.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 
00022 
00023 
00024 #ifdef HAVE_CONFIG_H
00025     #include <config.h>
00026 #endif
00027 
00028 #include <wolfssl/wolfcrypt/settings.h>
00029 
00030 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
00031 
00032 #include <wolfssl/wolfcrypt/chacha20_poly1305.h>
00033 #include <wolfssl/wolfcrypt/error-crypt.h>
00034 #include <wolfssl/wolfcrypt/logging.h>
00035 #include <wolfssl/wolfcrypt/chacha.h>
00036 #include <wolfssl/wolfcrypt/poly1305.h>
00037 
00038 #ifdef NO_INLINE
00039 #include <wolfssl/wolfcrypt/misc.h>
00040 #else
00041 #define WOLFSSL_MISC_INCLUDED
00042 #include <wolfcrypt/src/misc.c>
00043 #endif
00044 
00045 #ifdef CHACHA_AEAD_TEST
00046 #include <stdio.h>
00047 #endif
00048 
00049 #define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER  0
00050 #define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16
00051 
00052 static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]);
00053 static int calculateAuthTag(
00054                   const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
00055                   const byte* inAAD, const word32 inAADLen,
00056                   const byte *inCiphertext, const word32 inCiphertextLen,
00057                   byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]);
00058 
00059 int wc_ChaCha20Poly1305_Encrypt(
00060                 const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
00061                 const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
00062                 const byte* inAAD, const word32 inAADLen,
00063                 const byte* inPlaintext, const word32 inPlaintextLen,
00064                 byte* outCiphertext,
00065                 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
00066 {
00067     int err;
00068     byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
00069     ChaCha chaChaCtx;
00070 
00071     /* Validate function arguments */
00072 
00073     if (!inKey || !inIV ||
00074         !inPlaintext || !inPlaintextLen ||
00075         !outCiphertext ||
00076         !outAuthTag)
00077     {
00078         return BAD_FUNC_ARG;
00079     }
00080 
00081     XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
00082 
00083     /* Create the Poly1305 key */
00084     err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
00085     if (err != 0) return err;
00086 
00087     err = wc_Chacha_SetIV(&chaChaCtx, inIV,
00088                            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
00089     if (err != 0) return err;
00090 
00091     err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
00092                              CHACHA20_POLY1305_AEAD_KEYSIZE);
00093     if (err != 0) return err;
00094 
00095     /* Encrypt the plaintext using ChaCha20 */
00096     err = wc_Chacha_Process(&chaChaCtx, outCiphertext, inPlaintext,
00097                             inPlaintextLen);
00098     /* Calculate the Poly1305 auth tag */
00099     if (err == 0)
00100         err = calculateAuthTag(poly1305Key,
00101                                inAAD, inAADLen,
00102                                outCiphertext, inPlaintextLen,
00103                                outAuthTag);
00104     ForceZero(poly1305Key, sizeof(poly1305Key));
00105 
00106     return err;
00107 }
00108 
00109 
00110 int wc_ChaCha20Poly1305_Decrypt(
00111                 const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
00112                 const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
00113                 const byte* inAAD, const word32 inAADLen,
00114                 const byte* inCiphertext, const word32 inCiphertextLen,
00115                 const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
00116                 byte* outPlaintext)
00117 {
00118     int err;
00119     byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
00120     ChaCha chaChaCtx;
00121     byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
00122 
00123     /* Validate function arguments */
00124 
00125     if (!inKey || !inIV ||
00126         !inCiphertext || !inCiphertextLen ||
00127         !inAuthTag ||
00128         !outPlaintext)
00129     {
00130         return BAD_FUNC_ARG;
00131     }
00132 
00133     XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag));
00134     XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
00135 
00136     /* Create the Poly1305 key */
00137     err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
00138     if (err != 0) return err;
00139 
00140     err = wc_Chacha_SetIV(&chaChaCtx, inIV,
00141                            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
00142     if (err != 0) return err;
00143 
00144     err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
00145                              CHACHA20_POLY1305_AEAD_KEYSIZE);
00146     if (err != 0) return err;
00147 
00148     /* Calculate the Poly1305 auth tag */
00149     err = calculateAuthTag(poly1305Key,
00150                            inAAD, inAADLen,
00151                            inCiphertext, inCiphertextLen,
00152                            calculatedAuthTag);
00153 
00154     /* Compare the calculated auth tag with the received one */
00155     if (err == 0 && ConstantCompare(inAuthTag, calculatedAuthTag,
00156                                     CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0)
00157     {
00158         err = MAC_CMP_FAILED_E;
00159     }
00160 
00161     /* Decrypt the received ciphertext */
00162     if (err == 0)
00163         err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext,
00164                                 inCiphertextLen);
00165     ForceZero(poly1305Key, sizeof(poly1305Key));
00166 
00167     return err;
00168 }
00169 
00170 
00171 static int calculateAuthTag(
00172                 const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
00173                 const byte *inAAD, const word32 inAADLen,
00174                 const byte *inCiphertext, const word32 inCiphertextLen,
00175                  byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
00176 {
00177     int err;
00178     Poly1305 poly1305Ctx;
00179     byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1];
00180     word32 paddingLen;
00181     byte little64[8];
00182 
00183     XMEMSET(padding, 0, sizeof(padding));
00184 
00185     /* Initialize Poly1305 */
00186 
00187     err = wc_Poly1305SetKey(&poly1305Ctx, inAuthKey,
00188                             CHACHA20_POLY1305_AEAD_KEYSIZE);
00189     if (err)
00190     {
00191         return err;
00192     }
00193 
00194     /* Create the authTag by MAC'ing the following items: */
00195 
00196     /* -- AAD */
00197 
00198     if (inAAD && inAADLen)
00199     {
00200         err = wc_Poly1305Update(&poly1305Ctx, inAAD, inAADLen);
00201 
00202         /* -- padding1: pad the AAD to 16 bytes */
00203 
00204         paddingLen = -(int)inAADLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
00205         if (paddingLen)
00206         {
00207             err += wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
00208         }
00209 
00210         if (err)
00211         {
00212             return err;
00213         }
00214     }
00215 
00216     /* -- Ciphertext */
00217 
00218     err = wc_Poly1305Update(&poly1305Ctx, inCiphertext, inCiphertextLen);
00219     if (err)
00220     {
00221         return err;
00222     }
00223 
00224     /* -- padding2: pad the ciphertext to 16 bytes */
00225 
00226     paddingLen = -(int)inCiphertextLen &
00227                                   (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
00228     if (paddingLen)
00229     {
00230         err = wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
00231         if (err)
00232         {
00233             return err;
00234         }
00235     }
00236 
00237     /* -- AAD length as a 64-bit little endian integer */
00238 
00239     word32ToLittle64(inAADLen, little64);
00240 
00241     err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
00242     if (err)
00243     {
00244         return err;
00245     }
00246 
00247     /* -- Ciphertext length as a 64-bit little endian integer */
00248 
00249     word32ToLittle64(inCiphertextLen, little64);
00250 
00251     err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
00252     if (err)
00253     {
00254         return err;
00255     }
00256 
00257     /* Finalize the auth tag */
00258 
00259     err = wc_Poly1305Final(&poly1305Ctx, outAuthTag);
00260 
00261     return err;
00262 }
00263 
00264 
00265 static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8])
00266 {
00267     XMEMSET(outLittle64, 0, 8);
00268 
00269     outLittle64[0] = (byte)(inLittle32 & 0x000000FF);
00270     outLittle64[1] = (byte)((inLittle32 & 0x0000FF00) >> 8);
00271     outLittle64[2] = (byte)((inLittle32 & 0x00FF0000) >> 16);
00272     outLittle64[3] = (byte)((inLittle32 & 0xFF000000) >> 24);
00273 }
00274 
00275 
00276 #endif /* HAVE_CHACHA && HAVE_POLY1305 */
00277