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